2009-02-26 94 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); 
    } 
}