C#:声明和使用不同类型的generics类列表,如何?
具有以下generics类,其中包含string, int, float, long
作为类型:
public class MyData { private T _data; public MyData (T value) { _data = value; } public T Data { get { return _data; } } }
我想获得一个MyData
的列表,其中每个项目将是不同的T
我希望能够从列表中访问项目并获取其值,如下面的代码所示:
MyData myData = _myList[0]; // Could be , , ... SomeMethod (myData.Data);
其中SomeMethod()
声明如下:
public void SomeMethod (string value); public void SomeMethod (int value); public void SomeMethod (float value);
更新:
SomeMethod()
来自我无法控制的另一个层类, SomeMethod(object)
不存在。
但是,我似乎无法找到让编译器开心的方法。
有什么建议?
谢谢。
代表们可以真正帮助简化这一点,并且仍然保持类型安全:
public void TestMethod1() { Action intInvoke = (o, data) => o.SomeMethod(data); Action stringInvoke = (o, data) => o.SomeMethod(data); var list = new List { new MyData { Data = 10, OnTypedInvoke = intInvoke }, new MyData { Data = "abc", OnTypedInvoke = stringInvoke } }; var someClass = new SomeClass(); foreach (var item in list) { item.OnInvoke(someClass); } } public abstract class MyData { public Action OnInvoke; } public class MyData : MyData { public T Data { get; set; } public Action 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); } }
我认为您遇到的问题是因为您正在尝试创建generics类型,然后创建该generics类型的列表。 您可以通过外包您尝试支持的数据类型(例如IData元素)来完成您尝试执行的操作,然后使用IData约束创建MyDatagenerics。 这样做的缺点是你必须创建自己的数据类型来表示你正在使用的所有原始数据类型(string,int,float,long)。 它可能看起来像这样:
public class MyData where T : IData { public T Data { get; private set; } public MyData (T value) { Data = value; } } public interface IData { T Data { get; set; } void SomeMethod(); } //you'll need one of these for each data type you wish to support public class MyString: IData { public MyString(String value) { Data = value; } public void SomeMethod() { //code here that uses _data... Console.WriteLine(Data); } public string Data { get; set; } }
然后你的实现将是这样的:
var myData = new MyData(new MyString("new string")); // Could be MyString, MyInt, ... myData.Data.SomeMethod();
这是一个更多的工作,但你得到了你想要的function。
更新:从您的界面中删除SomeMethod,然后执行此操作
SomeMethod(myData.Data.Data);
只需使用ArrayList并忘记MyData
类型。
ArrayList myStuff = getStuff(); float x = myStuff.OfType().First(); SomeMethod(x); string s = myStuff.OfType().First(); SomeMethod(s);
MyData
的问题在于您希望编译器检查仅在运行时已知的类型。 编译器检查编译时已知的类型。
你不能按照你想要的方式去做。
初始化generics类的实例时,它将绑定到特定类型。 由于您希望在列表中保存不同类型的对象,因此必须创建一个绑定到最小公分母的实例 – 在您的情况下它是Object。
但是,这意味着Data属性现在将返回Object类型的对象。 编译器无法在编译时推断出实际的数据类型,因此可以选择适当的SomeMethod
重载。
您必须提供SomeMethod
的重载,将Object作为参数,或者删除在集合中保存不同类型的不同类型的要求。
或者您可以使用标准的IEnumerable
集合(如Array)并使用OfType<>
扩展方法来获取特定类型集合的子集。
在这种情况下,您需要MyData
因为这是这些类型的共同点。
您可以为SomeMethod
创建通用包装器并检查generics参数的类型,然后委托给适当的方法。
public void SomeMethod(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); } }
一会儿建议的通配符。 关闭为“将无法修复”:(
generics允许您在创建列表时为整个列表指定一种类型,例如,将创建一个用于存储int的列表,如下所示
var myData = new MyData();
如果要在同一通用列表中存储多个类型,可以为这些类型指定公共基本类型或接口。 不幸的是,在您的情况下,您要存储的类型的唯一公共基类型将是object。
var myData = new MyData
但您可以使用非通用列表来存储对象。
从非genericsMyData
类inheritanceMyData
并列出该列表。
这样,就无法自动解决过载问题。 你必须手动完成。
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 : MyData { protected override object GetData() { return Data; } protected override Type GetDataType() { return typeof(T); } public new T Data { get { ... } } }