2009-12-03 41 views
3

有沒有辦法使用一個泛型類的集合,而不提供基礎類型? 讓我們來解釋一下:在c#中定義較少的泛型?

這裏是想什麼,我有:

class TimeSerie<TValue> { 
enter code here 
} 

List<TimeSerie<?>> blah; 

這裏是我到目前爲止做:

class TimeSerie {} 
class TypedTimeSerie<TValue> : TimeSerie {} 

List<TimeSerie> blah; 

所以,沒有辦法用漂亮首先解決方案(儘管我猜這會在嘗試投射時產生問題,例如對於循環...)

+0

你可以做列表>等等,但我很好奇這將如何有用。 – 2009-12-03 15:48:49

+6

我們稱這個功能爲「嘟嘟型」。也就是說,你會說「這是一個愚蠢的時間表列表」,編譯器必須弄清楚「笨拙」的含義。特別適用於「嘟嘟」是匿名類型的情況。我們認爲它適用於C#4,但最終決定此次不實施它。也許在假設的未來版本中。如果您對此功能有非常棒的場景,請隨時通過電子郵件發送給我(來自我博客上的聯繫人鏈接)。我們擁有的場景越多,未來實際發佈的功能就越有可能。 – 2009-12-03 16:02:09

回答

8

您可以使用使用代碼通用太...但在某些時候您必須指定類型論據。如果不知道類型參數,您將無法創建泛型類型的實例。如果必須,您可以在執行時使用反射來提供該信息,但它必須在某處

+2

爲了澄清,我認爲Jon的意思是代替'List > blah;'你需要'List > blah;'其中T是該聲明出現的類或方法的泛型參數。 – 2009-12-03 15:49:10

+0

我是唯一一個看到Jon Skeet回答並給他豎起大拇指甚至沒有閱讀答案的人嗎? – 2009-12-03 15:56:32

+5

@大衛:請不要這樣做!我每天都會在答案中犯錯......如果他們沒有被社羣接受,他們會一直犯錯誤:( – 2009-12-03 16:01:11

1

我沒有看到基於你的問題你爲什麼不能從ICollection<T>List<T>派生自定義集合(或者自ICollection派生,並委託調用List<T>你在內部存儲類型的字段?

(這是完全可能我只是沒有得到它,但你可以給一個小一點的示例代碼?)

1

爲什麼不呢?

List<TimeSerie<Object>> blah; 

然後你指定對象後,還要定義你的基地相應地上課。

+0

嗡嗡聲,意味着繼承與泛型一起遞歸地工作,這是我沒有意識到的。 很高興知道! – Wam 2009-12-03 15:52:07

+0

這不起作用:列表> blah =新列表>();原因不能隱式轉換類型'System.Collections.Generic.List >'到'System.Collections.Generic.List >'(CS0029)]「 – ShuggyCoUk 2009-12-07 22:38:05

1

需要注意的是一些「喃喃自語」是可能相對於匿名類型,非常感謝C#兩點:

  1. 類型推斷
  2. 相同的匿名類型

的統一。如果你是快樂的依靠這兩件事仍然是固定的(對此沒有保證,特別是與2有關),那麼以下內容可能會有用。

public static class Mumble 
{ 
    public static HashSet<T> HashSet<T>(T prototype) 
    { 
     return new HashSet<T>(); 
    } 

    public static List<T> List<T>(T prototype) 
    { 
     return new List<T>(); 
    } 
} 

您可以使用它像這樣:

var set = MumbleSet(new { Foo="", Bar="", Baz=0 }); 
var list = MumbleList(new { Foo="", Bar="", Baz=0 }); 
set.Add(new { Foo="x", Bar="y", Baz=1 }); 
set.Add(new { Foo="a", Bar="b", Baz=1 }); 
list.Add(new { Foo="a", Bar="b", Baz=1 }); 
var intersection = list.Intersect(set); 
var concat = list.Concat(set); 

這,你必須要在方法中的其他地方填充到一些其他的收集使用匿名類型的案件效果很好。常見的用法是將數據庫查詢讀入一個集合中,以便後面檢查是否存在於循環中,將此表示爲一系列linq查詢太麻煩或太昂貴。

爲了您的激勵例子中,你將不得不增加以下內容:

class TimeSerie<TValue> 
{ 
    // or some other constructor equivalent 
    public TimeSerie(TValue value) { /* assign the value */ } 
} 

static class TimeSerieMumble 
{ 
    public static TimeSerie<TValue> New<TValue>(TValue value) 
    { 
     return new TimeSerie<TValue>(value); 
    } 
} 

然後,你可以使用的代碼如下所示:

var tsList = Mumble.List(TimeSerieMumble.New(new { Name="", Value=0 })); 
foreach (var x in from c select new { c.Name, c.Value }) 
{ 
    tsList.Add(TimeSerieMumble.New(new { x.Name, x.Value })); 
} 

喃喃其中「泄漏」到公共API不在C#3中是可行的。5,除非類型要通過一系列類型推斷的泛型方法與上例相同。考慮到調用代碼所需的扭曲,我從未見過這種情況是有用的。我不認爲這會提高可讀性。根據經驗,在Name/Value示例中使用兩個以上的嘟嘟聲可能會導致嚴重的併發症。

0

正如其他人所說,在C#中沒有簡單的方法來做到這一點。 但是,如果它真的很重要,它可以使用一些額外的類型忠實地編碼這種模式,雖然這是一個有點難看:

interface ITimeSeriesUser<X> { 
    X Use<T>(TimeSeries<T> series); 
} 

interface ITimeSeriesUser { 
    void Use<T>(TimeSeries<T> series); 
} 

interface ITimeSeries { 
    X Apply<X>(ITimeSeriesUser<X> user); 
    void Apply(ITimeSeriesUser user); 
} 

class TimeSeries<T> : ITimeSeries { 
    X Apply<X>(ITimeSeriesUser<X> user) { return user.Use(this); } 
    void Apply(ITimeSeriesUser user) { return user.Use(this); } 

    /* Your existing code goes here */ 
} 

現在你可以創建一個List<ITimeSeries>實例持有TimeSeries<T> 值不論其類型參數,並且您可以使用​​ 實現來操縱它們。顯然這需要相當多的樣板, 但如果你需要一個忠實的方式來表達TimeSeries<?>的概念,那麼這可能是你最好的選擇。