uso usando pueden partir objeto metodos inferir genericos generico crear c# .net generics

usando - no se pueden inferir a partir del uso c#



Colección de tipos genéricos. (9)

Si tengo una clase genérica:

public class MyClass<T> { public T Value; }

Quiero instanciar varios elementos tales como ...

new MyClass<string> new MyClass<int>

... y añadirlos a una colección. ¿Cómo defino la colección para que pueda contener una lista de tipos genéricos? Luego quiero recorrer la colección en algún punto y usar la propiedad Value. ¿Posible?


Creo que el problema aquí es que las clases genéricas realmente no son del mismo tipo. Son simplemente plantillas que crean nuevos tipos enteros en tiempo de compilación (si entiendo correctamente). Por lo tanto, MyClass<int> y MyClass<string> son tipos completamente diferentes, de acuerdo con el tiempo de ejecución. También podrían ser MyIntClass y MyStringClass , que obviamente no puedes tener en la misma lista sin antes clasificarlos. No heredan (necesariamente) la misma clase base, implementan las mismas interfaces o cualquier otra cosa. Son tan diferentes como cualquiera de los otros dos tipos, y usted tiene que tratarlos como tales (aunque crea que lo sabe mejor).

Por supuesto, puede hacer que implementen una interfaz, heredar un objeto base o cualquiera de las otras opciones ya dadas. Echa un vistazo a la respuesta de commongenius para una buena manera de hacer esto.


Creo que toda su colección tendría que ser del mismo tipo MyClass (como en T tendría que ser la misma), porque el compilador no sabrá qué tipos ha agregado a qué elementos de la colección.

En otras palabras, si tuviera que agregar 2 elementos a una lista:

list.Add(new MyClass<string>()); list.Add(new MyClass<int>());

luego intenta hacer referencia a uno:

var myItem = list[1];

El compilador no sabe qué genérico se asignó a la lista MyClass en el elemento 1 , porque los elementos se agregan en tiempo de ejecución, pero los genéricos se determinan en tiempo de compilación.

Estoy bastante seguro de que lo que quieres hacer no se puede hacer.

Si conoce el número de elementos de antemano, ¿quizás podría usar un 1 ?


Desde .Net 3 ha habido una clase CompositeCollection que permite contener múltiples artículos únicos o incluso colecciones. Es utilizado por los desarrolladores de WPF para almacenar y mostrar diferentes elementos en Xaml. Pero eso no significa que no se pueda usar en situaciones que no sean WPF.

Aquí hay un ejemplo donde almaceno cosas diferentes desde cadenas a decimales y extraigo y enumero sobre todos los elementos, luego elementos de un tipo específico:

CompositeCollection cc = new CompositeCollection(); cc.Add(1); cc.Add("Item One"); cc.Add(1.0M); cc.Add(1.0); cc.Add("Done"); Console.WriteLine ("Every Item"); foreach (var element in cc) Console.WriteLine ("/t" + element.ToString()); Console.WriteLine (Environment.NewLine + "Just Strings"); foreach (var str in cc.OfType<string>()) Console.WriteLine ("/t" + str); /* Outputs: Every Item 1 Item One 1.0 1 Done Just Strings Item One Done */


Desea tener una colección de MyClass para la cual el valor del parámetro de tipo T sea diferente en cada instancia. Esto no es posible en .NET; carece del equivalente al comodín de Java (?). Lo que debe hacer en su lugar es crear una clase base o interfaz no genérica, que MyClass pueda implementar. Por ejemplo:

public interface IMyClass { object Value { get; set; } } public class MyClass<T> : IMyClass { public T Value { get; set; } object IMyClass.Value { get { return Value; } set { Value = (T)value; } } } List<IMyClass> m = new List<IMyClass> { new MyClass<string>(), new MyClass<int> };


Haga que su clase genérica se herede de una base no genérica, o implemente una interfaz no genérica. Luego, puede tener una colección de este tipo y convertirla dentro del código que use para acceder a los contenidos de la colección.

Aquí hay un ejemplo.

public abstract class MyClass { public abstract Type Type { get; } } public class MyClass<T> : MyClass { public override Type Type { get { return typeof(T); } } public T Value { get; set; } } // VERY basic illustration of how you might construct a collection // of MyClass<T> objects. public class MyClassCollection { private Dictionary<Type, MyClass> _dictionary; public MyClassCollection() { _dictionary = new Dictionary<Type, MyClass>(); } public void Put<T>(MyClass<T> item) { _dictionary[typeof(T)] = item; } public MyClass<T> Get<T>() { return _dictionary[typeof(T)] as MyClass<T>; } }


IList

No hay manera de definir una colección genérica que pueda aceptar cualquier tipo de su clase genérica ... es decir, IList<MyClass> . Las clases genéricas son solo un atajo para que el desarrollador ahorre al escribir un montón de código repetitivo, pero en el momento de la compilación, cada sabor de la clase genérica se traduce en un concreto. es decir, si tiene MyClass<string> , MyClass<int> , MyClass<bool> entonces el compilador generará 3 clases separadas y distintas. La única forma de hacer lo que quiere es tener una interfaz para su genérico.

public interface IMyGeneric { Type MyType { get; set;} } class MyGeneric<T> : IMyGeneric { public MyGeneric() { MyType = typeof(T); } public Type MyType { get; set; } }

y luego puedes decir

IList<IMyGeneric> list = new List<IMyGeneric>(); list.add(new MyGeneric<string>()); list.add(new MyGeneric<int>());


La única forma en que puedo pensar, fuera de mi cabeza, es la siguiente (envuelta en una aplicación de consola para realizar pruebas):

class Program { static void Main(string[] args) { var x = new MyClass<string>() { Value = "34" }; var y = new MyClass<int>() { Value = 3 }; var list = new List<IMyClass>(); list.Add(x); list.Add(y); foreach (var item in list) { Console.WriteLine(item.GetValue); } } private interface IMyClass { object GetValue { get; } } private class MyClass<T> : IMyClass { public T Value; public object GetValue { get { return Value; } } } }

es decir, haga que MyClass implemente una interfaz vacía y luego cree sus colecciones como una que contiene instancias de clases que implementan esa interfaz.

Actualización: He agregado un método "GetValue" a la interfaz que le permite acceder al "Valor" de la instancia de MyClass como un objeto. Esto es tan bueno como se va a conseguir, afaik, si quieres tener una colección que contenga tipos mixtos.


Querrá definir una clase base para MyClass, entonces sus colecciones serán una Lista de clases base. Ex:

void Main() { var a = new MyClass<string>(); var b = new MyClass<int>(); var c = new List<MyBase>(); c.Add(a); c.Add(b); } public class MyBase { } // Define other methods and classes here public class MyClass<T> : MyBase { public T Value { get; set;} }


Tengo interfaces en la mayoría de mis tipos genéricos con miembros "sin tipo":

private interface IMyClass { object UntypedValue { get; } } private class MyClass<T> : IMyClass { T Value { get; set; } object UntypedValue { get { return Value; } } }

También puede hacer esto mediante el uso de una implementación de interfaz explícita, pero en mi opinión, es mucho más fácil si usa un nombre separado. (También hay algunos consejos de CA sobre la implementación de la interfaz explícita)