2010-07-09 136 views
23

,如果我有一個泛型類:集合泛型類型

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

我想要實例化的幾個項目,如...

new MyClass<string> 
new MyClass<int> 

...,並將它們添加到集合。如何定義集合以便它可以包含泛型類型列表?然後我想在某個時候遍歷集合,並使用Value屬性。可能?

+0

你怎麼宣佈你的班?你如何定義後備集合? – Oded 2010-07-09 18:16:45

+0

這只是一個「假設」,或者你正在試圖用作解決方案的一部分?我問,因爲給了更多的上下文,我們可能會建議一個更好的答案.. :) – Rob 2010-07-09 18:37:16

+0

幾乎相同的問題後來轉貼(我投票結束,但可能沒有它,因爲它是如此之久):http: //stackoverflow.com/q/3777057/590790 – 2015-12-25 15:20:31

回答

23

讓您的泛型類從非泛型基類繼承,或實現非泛型接口。然後,您可以收集此類型的集合,並在您用來訪問集合內容的任何代碼中進行投射。

下面是一個例子。

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

返回類型是一個有趣的變化。 – 2010-07-09 18:55:56

+1

你的解決方案絕對是優雅的。保持類型的內部字典確實可以實現更簡單的訪問方法。 – 2010-07-12 14:57:23

+0

此外,您現在可以使用'dynamic'關鍵字:http://msdn.microsoft.com/en-us/library/dd264736.aspx – Tommy 2014-02-19 19:31:21

1

我相信你的集合必須具有相同的MyClass類型(因爲在T中必須是相同的),因爲編譯器不會知道你將哪些類型添加到集合中的哪些元素。

換句話說,如果你要2個元素添加到列表中:

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

然後嘗試引用一個:

var myItem = list[1]; 

編譯器不知道什麼一般被分配到元素1上的MyClass列表,因爲元素是在運行時添加的,但泛型是在編譯時確定的。

我很確定你想做的事情無法完成。


如果您事先知道元素的數量,也許您可​​以使用Tuple

7

我能想到的唯一的辦法,把我的頭頂部如下(在一個控制檯應用程序進行測試包裹起來):

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

即有無MyClass的實現一個空的接口,然後創建集合作爲持有實現該接口的類的實例的集合。

更新: 我添加了一個「的GetValue」的方法,可以讓你訪問的MyClass的實例的「價值」爲對象的接口。如果你想擁有一個擁有混合類型的集合,那麼它就像它將要得到的一樣好,afaik。

+0

良好的調用 - 這是我使用基類的等價答案:) – 2010-07-09 18:21:12

+0

但是,如何訪問value屬性? – 2010-07-09 18:23:56

+0

問題是他想要一個Value屬性,該屬性最終具有正確的類型,但無法確定。 – CodingWithSpike 2010-07-09 18:25:21

3

你會想爲MyClass定義一個基類,那麼你的集合將是一個基類列表。例如:

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

在您的示例中,將MyBase標記爲抽象類以更清楚地表明它的意圖可能是值得的.. :) – Rob 2010-07-09 18:22:22

+0

有趣...如何遍歷列表並檢查內容Value屬性? – Jeremy 2010-07-09 18:25:18

+0

+1,和我的回答非常相似:) – Rob 2010-07-09 18:34:27

3

你想擁有MyClass的集合有類型參數T的值在每種情況不同。這在.NET中是不可能的。它缺少Java通配符(?)的等價物。您需要做的是創建一個非泛型的基類或接口,MyClass可以實現該基類或接口。例如:

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

@ commongenius,你確認它不會編譯?它在VS2k8中爲我編譯得很好 – Rob 2010-07-09 18:33:42

+0

當我發佈我的評論時,原來的帖子已經改變了。我相應地改變了我的評論。 – 2010-07-09 18:38:48

3

我有我的大部分泛型類型與「無類型」的成員接口:

private interface IMyClass 
{ 
    object UntypedValue { get; } 
} 

private class MyClass<T> : IMyClass 
{ 
    T Value { get; set; } 

    object UntypedValue { get { return Value; } } 
} 

您還可以通過使用顯式接口實現的做到這一點,但在我看來,通過使用單獨的名稱更容易。(上有顯式接口實現一些CA提示以及)

+0

+1提供鍵入和未鍵入的值。 – 2010-07-09 18:55:05

1

的IList

沒有辦法定義一個通用集合,可以接受你的泛型類...即IList<MyClass>的任何味道。泛型類只是開發人員在編寫一堆重複代碼時節省的一個捷徑,但在編譯時泛型類的每種風格都被轉化爲具體的。即如果你有MyClass<string>,MyClass<int>,MyClass<bool>那麼編譯器將生成3個獨立和不同的類。做你想做的事情的唯一方法是爲你的泛型提供一個接口。

public interface IMyGeneric { 
    Type MyType { get; set;}  
} 

class MyGeneric<T> : IMyGeneric { 

    public MyGeneric() { 
     MyType = typeof(T); 
    } 

    public Type MyType { 
     get; set; 
    } 
} 

,然後你可以說

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

我覺得這裏的問題是,泛型類真的不是同一類型的。它們只是在編譯時創建全新類型的模板(如果我理解正確的話)。因此,根據運行時間,MyClass<int>MyClass<string>完全不同的類型。他們可能是MyIntClassMyStringClass,你顯然不能在同一個列表中沒有先裝箱。他們不(必然)繼承相同的基類,實現相同的接口或其他任何東西。它們與其他任何兩種類型都不同,你必須像對待它們一樣對待它們(即使你認爲你知道的更好)。

當然,你可以讓他們實現一個接口,繼承一個基礎對象,或任何其他已經給出的選項。看看commongenius' answer是一個很好的方法來做到這一點。

1

由於淨3出現了CompositeCollection類,它允許多個獨特的項目,甚至藏品被包含在內。它由WPF開發人員用來在Xaml中存儲和顯示不同的項目。但這並不意味着它不能用於非WPF的情況。

這裏就是我的琴絃不同的東西存儲小數和提取,並列舉了所有項目,那麼一個特定類型的項目的例子:

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 

*/