2009-02-26 114 views
23

具有下列泛型类要包含下面string, int, float, long作为类型:C#:声明和使用不同类型的泛型类的列表,如何?

public class MyData<T> 
{ 
    private T _data; 

    public MyData (T value) 
    { 
     _data = value; 
    } 

    public T Data { get { return _data; } } 
} 

我试图得到MyData<T>一个列表,其中每个项目将是不同T

我希望能够从列表中访问某个项目,并得到其数值如下面的代码:

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

其中SomeMethod()声明如下:

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

更新:

SomeMethod()是来自另一层级我没有控制和SomeMethod(object)不存在。


但是,我似乎无法找到一种方法让编译器感到高兴。

有什么建议吗?

谢谢。

+0

你能对你的someMethod做什么详细点吗?我们可能会更好地帮助你。 – 2009-02-26 13:55:32

+0

SomeMethod所做的与此无关。我只是补充说SomeMethod(object)没有定义。 – 2009-02-26 14:11:47

+0

您的基本设计有缺陷。我建议问一个问题,详细说明需求和解决方案并征求建议。 – Will 2009-02-26 14:13:38

回答

8

代表可以真正帮助简化此,仍然保持事物类型安全:

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); 
    } 
} 
0

从非通用MyData类继承MyData<T>并列出该列表。

这样,您不能自动解决过载问题。你必须手动完成。

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 { ... } 
    } 
} 
+0

好的,现在我会使用它: 列表 list = new列表(); list.Add(new MyData ()); list.Add(new MyData ()); SomeMethod(list [0] .Data);不知怎的,我需要让SomeMethod()接受一个对象。 这不是我需要的不幸。 感谢您的回复。 Stecy – 2009-02-26 14:02:25

+0

是的,这就是为什么我说你应该通过考虑类型手动管理重载。泛型不支持直接的方式。 – 2009-02-26 14:49:45

1

在这种情况下,您需要MyData<object>,因为这是这些类型唯一共同的东西。

+2

MyData 如何允许调用SomeMethod(int)? – 2009-02-26 13:40:55

0

泛型可以在创建列表,例如用于存储INT列表会这样

var myData = new MyData<int>(); 

如果你想存储多种类型在同创建指定一种类型的整个列表通用列表中,您可以为这些类型指定通用基本类型或接口。不幸的是,在你的情况下,你想要存储的类型的唯一公共基类型是object。

var myData = new MyData<object>(); 

但是,您可以使用非通用列表来存储对象。

6

只需使用ArrayList并忘记MyData<T>类型。

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

MyData<T>的问题是,你希望编译器检查只在运行时已知的类型。编译器检查编译时已知的类型。

+0

谢谢!这是我个人问题的答案。试图跟踪BlockingCollection 的列表,然后通过GetQueue 进行检查,其中T:Interface方法是否在我的列表中存在类型T的队列,如果不存在,则实例化并返回新的空队列。但BlockingCollection 不能隐式转换为BlockingCollection ,甚至认为T:Interface,并且我无法为我的生活找到正确的协变/逆变/委托实现来执行此操作。 – Isaac 2017-06-21 06:55:03

3

你不能按你想要的方式去做。

当泛型类的实例被初始化时,它被绑定到特定的类型。既然你想在你的列表中保存不同类型的对象,你必须创建一个绑定到最小公分母的实例 - 在你的情况下它是Object。

但是,这意味着Data属性现在将返回一个Object类型的对象。编译器无法在编译时推断实际的数据类型,所以它可以选择合适的过载。

您必须提供SomeMethod的重载,将Object作为参数,或者删除在集合中保存不同类型的需求。

或者您可以使用标准IEnumerable集合(如Array)并使用OfType<>扩展方法获取特定类型集合的子集。

+0

我担心它会解析为使用对象。 .. 但是,我不能使用一个对象,因为SomeMethod是从库中,我不能改变它不会接受对象的事实... 此外,我不想切换( )在变量的类型... – 2009-02-26 14:07:33

1

建议通配符一会儿回here。关闭为“不会修复”:(

13

我认为你遇到的问题是因为你试图创建一个泛型类型,然后创建一个泛型类型的列表。你可以完成你试图通过将你试图支持的数据类型作为一个IData元素进行外包,然后用IData的约束来创建你的MyData泛型,其缺点是你必须创建自己的数据类型数据类型来表示你正在使用(字符串,整数,浮点,长),它可能看起来像这样的基本数据类型:

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; } 
} 

,然后你的实现是这样的:

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

这是一个更多的工作,但你得到了你要去的功能。

UPDATE:从你的接口 删除的someMethod,只是这样做

SomeMethod(myData.Data.Data); 
1

您可以SomeMethod创建一个通用的包装并检查通用参数的类型,然后委托给适当的方法。

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); 
    } 
}