usando tipos tipo ser referencia que instanciar genéricos genericos genericas debe colecciones clases c# .net generics list

c# - ser - tipos genéricos java



C#: declarar y usar una lista de clases genéricas con diferentes tipos, ¿cómo? (9)

Creo que el problema que estás teniendo es que estás tratando de crear un tipo genérico y luego creas una lista de ese tipo genérico. Puede lograr lo que intenta hacer contratando los tipos de datos que está tratando de admitir, digamos como un elemento IData, y luego crear su MyData genérico con una restricción de IData. La desventaja de esto sería que tendría que crear sus propios tipos de datos para representar todos los tipos de datos primitivos que está utilizando (cadena, int, flotante, largo). Puede parecerse a esto:

public class MyData<T, C> where T : IData<C> { public T Data { get; private set; } public MyData (T value) { Data = value; } } public interface IData<T> { T Data { get; set; } void SomeMethod(); } //you''ll need one of these for each data type you wish to support public class MyString: IData<string> { public MyString(String value) { Data = value; } public void SomeMethod() { //code here that uses _data... Console.WriteLine(Data); } public string Data { get; set; } }

y luego tu implementación sería algo así como:

var myData = new MyData<MyString, string>(new MyString("new string")); // Could be MyString, MyInt, ... myData.Data.SomeMethod();

es un poco más de trabajo pero obtienes la funcionalidad que estabas buscando.

ACTUALIZACIÓN: elimine SomeMethod de su interfaz y simplemente haga esto

SomeMethod(myData.Data.Data);

Tener la siguiente clase genérica que contendría string, int, float, long as the type:

public class MyData<T> { private T _data; public MyData (T value) { _data = value; } public T Data { get { return _data; } } }

Estoy tratando de obtener una lista de MyData<T> donde cada elemento sería de T diferente.

Quiero poder acceder a un elemento de la lista y obtener su valor como en el siguiente código:

MyData<> myData = _myList[0]; // Could be <string>, <int>, ... SomeMethod (myData.Data);

donde SomeMethod() se declara de la siguiente manera:

public void SomeMethod (string value); public void SomeMethod (int value); public void SomeMethod (float value);

ACTUALIZAR:

SomeMethod() es de otra clase de nivel que no tengo control y SomeMethod(object) no existe.

Sin embargo, parece que no puedo encontrar una manera de hacer feliz al compilador.

¿Alguna sugerencia?

Gracias.


En ese caso, necesita MyData<object> ya que es lo único que esos tipos tienen en común.


Los genéricos le permiten especificar un tipo para toda la lista cuando crea la lista, por ejemplo, una lista para almacenar int se crearía así

var myData = new MyData<int>();

Si desea almacenar varios tipos en la misma lista genérica, puede especificar un tipo de base o interfaz común para esos tipos. Desafortunadamente, en su caso, el único tipo de base común para los tipos que desea almacenar sería un objeto.

var myData = new MyData<object>();

Pero puedes usar la lista no genérica para almacenar objetos.


Puede crear un contenedor genérico para SomeMethod y verificar el tipo del argumento genérico, luego delegarlo al método apropiado.

public void SomeMethod<T>(T value) { Type type = typeof(T); if (type == typeof(int)) { SomeMethod((int) (object) value); // sadly we must box it... } else if (type == typeof(float)) { SomeMethod((float) (object) value); } else if (type == typeof(string)) { SomeMethod((string) (object) value); } else { throw new NotSupportedException( "SomeMethod is not supported for objects of type " + type); } }


Simplemente use una ArrayList y olvide el tipo MyData<T> .

ArrayList myStuff = getStuff(); float x = myStuff.OfType<float>().First(); SomeMethod(x); string s = myStuff.OfType<string>().First(); SomeMethod(s);

El problema con MyData<T> es que esperas que el compilador compruebe un tipo que solo se conoce en tiempo de ejecución. Los compiladores comprueban los tipos que se conocen en tiempo de compilación.


MyData<T> de una clase MyData no genérica y haga una lista de eso.

De esta forma, no puede resolver automáticamente la sobrecarga. Tienes que hacerlo de forma manual.

abstract class MyData { protected abstract object GetData(); protected abstract Type GetDataType(); public object Data { get { return GetData(); } } public Type DataType { get { return GetDataType(); } } } class MyData<T> : MyData { protected override object GetData() { return Data; } protected override Type GetDataType() { return typeof(T); } public new T Data { get { ... } } }


Los comodines sugeridos hace un tiempo aquí . Cerrado como "no arreglará" :(


No puedes hacerlo de la manera que quieras.

Cuando se inicializa una instancia de una clase genérica, está vinculada a un tipo particular. Como desea mantener objetos de diferentes tipos en su lista, debe crear una instancia vinculada al mínimo común denominador, en su caso es Object.

Sin embargo, eso significa que la propiedad Data ahora devolverá un objeto de tipo Object. El compilador no puede inferir el tipo de datos real en tiempo de compilación, por lo que puede elegir la sobrecarga SomeMethod adecuada.

SomeMethod proporcionar una sobrecarga de SomeMethod que tome Object como parámetro o eliminar el requisito de mantener diferentes tipos diferentes en su colección.

O puede ir con una colección IEnumerable estándar (como Array) y usar el método de extensión OfType<> para obtener el subconjunto de la colección de un tipo particular.


Los delegados realmente pueden ayudar a simplificar esto, y aún así mantener las cosas seguras de tipo:

public void TestMethod1() { Action<SomeClass, int> intInvoke = (o, data) => o.SomeMethod(data); Action<SomeClass, string> stringInvoke = (o, data) => o.SomeMethod(data); var list = new List<MyData> { new MyData<int> { Data = 10, OnTypedInvoke = intInvoke }, new MyData<string> { Data = "abc", OnTypedInvoke = stringInvoke } }; var someClass = new SomeClass(); foreach (var item in list) { item.OnInvoke(someClass); } } public abstract class MyData { public Action<SomeClass> OnInvoke; } public class MyData<T> : MyData { public T Data { get; set; } public Action<SomeClass, T> OnTypedInvoke { set { OnInvoke = (o) => { value(o, Data); }; } } } public class SomeClass { public void SomeMethod(string data) { Console.WriteLine("string: {0}", data); } public void SomeMethod(int data) { Console.WriteLine("int: {0}", data); } }