2010-01-20 101 views
0

是這樣的可能嗎?是否可以在.net中創建一個通用約束類型的集合?

Dim l As New List(Of T As Type Where GetType(BaseClass).IsAssignableFrom(T)) 

注意,我的收藏將是類型的集合,類型T的不是對象 - 這是我所知道的是可能的。

ETA:

我已經到目前爲止與預期一致的答案 - 我不認爲這是可能的。

我試圖讓我的頭一輪是爲什麼下面就可以在編譯時解決,但不是我的例子:

Dim l as New List(Of T As BassClass) 

是檢查不,實際上,同樣的?

回答

2

您可以在您的收藏這樣的運行強制約束:

public class ConstrainedTypeCollection<TBaseType> : Collection<Type> 
{ 
    protected override void InsertItem(int index, Type item) 
    { 
     if (!typeof(TBaseType).IsAssignableFrom(item)) 
      throw new ArgumentException("The type is incompatible.", "item"); 

     base.InsertItem(index, item); 
    } 

    protected override void SetItem(int index, Type item) 
    { 
     if (!typeof(TBaseType).IsAssignableFrom(item)) 
      throw new ArgumentException("The type is incompatible.", "item"); 

     base.SetItem(index, item); 
    } 
} 

編輯:你也可以做到以下幾點只要您撥打得到充分的編譯時類型安全通用的Add<T>(),Contains<T>()Remove<T>()方法。

public class ConstrainedTypeCollection<TBaseType> : ICollection<Type> 
{ 
    private readonly List<Type> _collection = new List<Type>(); 

    public void Add<T>() 
     where T : TBaseType 
    { 
     _collection.Add(typeof(T)); 
    } 

    public bool Contains<T>() 
     where T : TBaseType 
    { 
     return _collection.Contains(typeof(T)); 
    } 

    public bool Remove<T>() 
     where T : TBaseType 
    { 
     return _collection.Remove(typeof(T)); 
    } 

    public int Count 
    { 
     get 
     { 
      return _collection.Count; 
     } 
    } 

    bool ICollection<Type>.IsReadOnly 
    { 
     get 
     { 
      return false; 
     } 
    } 

    public void Clear() 
    { 
     _collection.Clear(); 
    } 

    public void CopyTo(Type[] array, int arrayIndex) 
    { 
     _collection.CopyTo(array, arrayIndex); 
    } 

    public IEnumerator<Type> GetEnumerator() 
    { 
     return _collection.GetEnumerator(); 
    } 

    #region ICollection<Type> Members 

    void ICollection<Type>.Add(Type item) 
    { 
     VerifyType(item); 
     _collection.Add(item); 
    } 

    bool ICollection<Type>.Contains(Type item) 
    { 
     VerifyType(item); 
     return _collection.Contains(item); 
    } 

    bool ICollection<Type>.Remove(Type item) 
    { 
     VerifyType(item); 
     return _collection.Remove(item); 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    private void VerifyType(Type item) 
    { 
     if (!typeof(TBaseType).IsAssignableFrom(item)) 
      throw new ArgumentException("The type is incompatible.", "item"); 
    } 
} 
+0

感謝您的示例。這就是我已經做的,我只是想知道在編譯時是否有可能。 – Jules 2010-01-20 07:35:42

+1

檢查我的編輯另一個選項。 :) – 2010-01-20 08:13:37

+0

這太棒了。事實證明,它可以完成,但有一些相當不尋常的語法!你有沒有想過這個,或者你之前使用過它? – Jules 2010-01-20 16:26:57

0

不,不可以。泛型中的Type需要在編譯時解析。

+0

我向OP中添加了另一個問題。我今天感覺有點蠢,不明白爲什麼它不能在編譯時解決。 – Jules 2010-01-20 07:34:27

0

我不認爲有可能在編譯時進行靜態檢查。但是您可以重寫Add,AddRange和this []以在運行時檢查添加的元素。

2

檢查是不一樣的 - 在你的第一個例子中,你要求編譯器調用「IsAssignableFrom」方法,然後根據結果做一些事情。在第二個例子中,你要求編譯器的靜態類型檢查器做一些工作。

通常,編譯器在編譯期間不會調用任意代碼。

此外,請記住泛型的任何類型約束必須嵌入您的程序集元數據中。而且,您不能將任意代碼放入泛型類型約束中。

0

要做到這一點,您需要創建Type(Of TBase)類,然後創建它們的列表。 然後您可以嘗試確保Type(Of TBase)是靜態正確的。

但是在大多數情況下,如果需要從CLR類型創建Type(Of TBase),則只能動態保證。

0

可以實現遵守多個通用約束而不使用反射的東西的集合,但它非常惡劣。每個添加到集合的項目都必須用類對象包裝。如果集合應該裝東西限制爲I1I2,每個項目將被包裝在類型TI1泛型類的實例,並I2(約束,使得T:I1,I2),它實現了與泛型類型I1I2接口。集合本身將保存該接口類型的引用。

如果有人有興趣,我可以發佈更多的細節。

相關問題