rae - C#Genéricos y polimorfismo: ¿un oxímoron?
poemas con oximoron (6)
Parece que una vez que introduce un genérico en una jerarquía o interfaz de herencia, ya no puede usar esa familia de clases de forma polimórfica.
Correcto, es bastante similar a esta situación:
class StringContainer
{
}
class IntContainer
{
}
StringContainer container = new IntContainer(); // fails to compile
pero puedes hacer esto
class Container
{
}
class Container<T> : Container
{
}
Container container = new Container<String>(); // OK
Solo quiero confirmar lo que he entendido sobre los genéricos en C #. Esto surgió en un par de bases de código en las que he trabajado, donde se utiliza una clase base genérica para crear instancias derivadas seguras para el tipo. Un ejemplo muy simple de lo que estoy hablando,
public class SomeClass<T>
{
public virtual void SomeMethod(){ }
}
public class DeriveFrom :SomeClass<string>
{
public override void SomeMethod()
{
base.SomeMethod();
}
}
El problema surge cuando luego quiero usar instancias derivadas de una manera polimórfica.
public class ClientCode
{
public void DoSomethingClienty()
{
Factory factory = new Factory();
//Doesn''t compile because SomeClass needs a type parameter!
SomeClass someInstance = factory.Create();
someInstance.SomeMethod();
}
}
Parece que una vez que introduce un genérico en una jerarquía o interfaz de herencia, ya no puede usar esa familia de clases de forma polimórfica, excepto tal vez interna a sí misma. ¿Es eso cierto?
Creo que estás malinterpretando el punto de los genéricos. Los genéricos le permiten generalizar una clase que requiere un tipo, pero no se preocupa particularmente por qué tipo es. Por ejemplo, una List<string>
es una lista de cadenas, pero ¿qué sería una List
? Es un concepto bastante inútil tener una lista de nada.
Cada clase especializada (es decir, List<string>
) es su propio tipo distinto , y el compilador lo trata como tal. Es posible obtener el tipo genérico en sí mismo ( typeof(List<>)
por ejemplo), pero en la mayoría de los casos es inútil, y ciertamente no se puede hacer una instancia de él.
Creo que lo que estás buscando es:
SomeClass(of someType) someInstance = factory(of someType).Create(); or maybe SomeClass(of someType) someInstance = factory.Create(of someType)(); or SomeClass(of someType) someInstance = factory.Create();
Es posible tener un conjunto de clases de fábrica para crear diferentes clases genéricas, o tener una fábrica con un parámetro de tipo genérico para indicar qué tipo genérico debe crear (tenga en cuenta que en cualquier caso, el parámetro de tipo es el parámetro de tipo para el genérico). clase, en lugar de ser la clase genérica en sí). También es posible tener una fábrica que esté diseñada para devolver instancias de una forma particular de un tipo genérico.
Por lo que puedo ver, el código de consumo no necesita detalles específicos de la clase genérica (es decir, no depende de qué es T
). Entonces, ¿por qué no introduce la interfaz que SomeClass<T>
y utiliza la instancia de esta interfaz?
P.ej:
public interface ISome
{
void SomeMethod();
}
public class SomeClass<T>: ISome
{
public virtual void SomeMethod(){ }
}
public void DoSomethingClienty()
{
Factory factory = new Factory();
ISome someInstance = factory.Create();
someInstance.SomeMethod();
}
Ahora, las subclases de SomeClass<T>
pueden operar de manera diferente en diferentes T
s, pero el código de consumo no cambiará.
Preferiría usar la clase abstracta para actuar como base de todos los tipos genéricos.
public abstract class SomeClass
{
public abstract void SomeMethod();
}
public class SomeClass<T> : SomeClass
{
public override void SomeMethod() { }
}
public class DeriveFrom<String> : SomeClass<String>
{
public override void SomeMethod() { base.SomeMethod(); }
}
public Class ReflectionReport<T>
{
// This class uses Reflection to produce column-based grids for reporting.
// However, you need a type in order to know what the columns are.
}
... so, in another class you have...
public Class ReflectionReportProject {
ReflectionReport<Thang> thangReport = new ReflectionReport<Thang>();
ReflectionReport<Thong> thongReport = new ReflectionReport<Thong>();
... some more stuff ...
// Now, you want to pass off all of the reports to be processed at one time....
public ReflectionReport<????>[] ProvideReports()
{
return new ReflectionReport<????>[] { thangReport, thongReport } ;
}
}