2012-11-12 147 views
9

考慮下面的通用類:泛型類型參數的約束

public class Custom<T> where T : string 
{ 
} 

這將產生以下錯誤:

'string' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.

有另一種方式來約束我的泛型類可以使用哪些類型?

此外,我可以限制到多種類型?

E.G.

T can only be string, int or byte

+0

爲這些情況做的最好的事情是創建一個包裝類,或者採用更通用的東西(Object),並在構造函數中進行類型檢查。這很漂亮嗎?沒有。它會工作嗎?是。 – sybkar

+0

@sybkar,你的意思就像我的回答? – series0ne

回答

16
public class Custom<T> where T : string 

是不允許的,因爲只有T滿足那就是:stringstringsealed) - 使得它相當無意義作爲一種通用的。

Also, can I constrain to multiple types?

沒有 - 除非你做的,而不是約束通過反射運行時(靜態構造函數是做的一個方法 - 拋出一個異常,如果使用不當)

T can only be string, int or byte

威力使用類似IEquatable<T>的東西,但這並不會像您想的那樣限制它,所以最終:不。

你的東西可能做的是通過一個重載的工廠訪問它:

public abstract class Custom 
{ 
    public static Custom Create(int value) 
    { return new CustomImpl<int>(value); } 
    public static Custom Create(byte value) 
    { return new CustomImpl<byte>(value); } 
    public static Custom Create(string value) 
    { return new CustomImpl<string>(value); } 
    private class CustomImpl<T> : Custom 
    { 
     public CustomImpl(T val) { /*...*/ } 
    } 
} 
+0

感謝您的回答......我有一點自己玩。如果你有一分鐘​​,請看看我的答案,看看你的想法。任何建設性的批評是讚賞! :-) – series0ne

+0

「public class Custom where T:string ... is not allowed,because the only that that meets that is:string(string is sealed) - it makes it nothing pointless as a generic。」 - 同意,字符串本身是毫無意義的,但可以說我想限制爲String,StringBuilder和SecureString。這將是更有用的,但仍然是非法的,因爲字符串是密封的:-( – series0ne

+0

@activwerx,這是不是泛型支持 –

2

從我的經驗,我會說,我理解你爲什麼想有,stringint ......因爲一個通用基類ID類型字符串或int

但是這是肯定的,這是不可能的。由於此MSDN的描述說: http://msdn.microsoft.com/en-us/library/d5x73970%28v=vs.80%29.aspx

我們可以有一個constraing class(如串參考對象)或struct(值類型如int) 那麼混合字符串和INT將是不可能的

注意:錯誤因爲字符串是有意義的,因爲字符串是密封的,所以它不一定是通用的 - 字符串ID是我們需要的

1

在回顧這裏的答案後,我有一點點玩弄自己,我已經出現了與下面的實現,它檢查運行時約束而不是編譯時間。

// This example takes 3 parameters... 
public class GenericConstraint<T1, T2, T3> 
{ 
    public GenericConstraint(Type type) 
    { 
     if (!(type is T1) || !(type is T2) || !(type is T3)) 
     { 
      throw new Exception("This is not a supported type"); 
     } 
    } 
} 

現在我繼承了我的自定義類...

public class Custom<T> : GenericConstraint<string, int, byte> 
{ 
    public Custom() : base(typeof(T)) 
    { 
    } 
} 

現在,這將引發一個錯誤:

Custom<long> item = new Custom<long>(); 

這不!

Custom<byte> item2 = new Custom<byte>(); 

正如Marc Gravell所述,這不是繼承或泛型的好用法。通過繼承GenericConstraint從邏輯上思考,這只是限制繼承,並且也沒有正確使用類型層次結構。就泛型的使用而言,這實際上毫無意義!

因此,我有另一個解決方案作爲一個輔助方法來限制運行時的類型。這從繼承中釋放了對象,因此對類型層次結構沒有影響。

public static void ConstrainParameterType(Type parameterType, GenericConstraint constraintType, params Type[] allowedTypes) 
     { 
      if (constraintType == GenericConstraint.ExactType) 
      { 
       if (!allowedTypes.Contains<Type>(parameterType)) 
       { 
        throw new Exception("A runtime constraint disallows use of type " + parameterType.Name + " with this parameter."); 
       } 
      } 
      else 
      { 
       foreach (Type constraint in allowedTypes) 
       { 
        if (!constraint.IsAssignableFrom(parameterType)) 
        { 
         throw new Exception("A runtime constraint disallows use of type " + parameterType.Name + " with this parameter."); 
        } 
       } 
      } 
     } 

public enum GenericConstraint 
    { 
     /// <summary> 
     /// The type must be exact. 
     /// </summary> 
     ExactType, 

     /// <summary> 
     /// The type must be assignable. 
     /// </summary> 
     AssignableType 
    } 

現在這允許在普通對象的多個類型的限制,即使類型密封等

"public class Custom where T : string ... is not allowed, because the only T that meets that is: string (string is sealed) - making it rather pointless as a generic."

是的,這是沒有意義的,但在某些情況下,您可能希望將對象約束允許,例如;字符串,StringBuilder和SecureString。雖然這不提供編譯時間約束,但它確實提供了運行時約束,並且在約束中可以使用哪些類型的一些靈活性。

+4

不是一個偉大的使用泛型*或*繼承,IMO .... –

+0

但是,在我們的選擇受到C#和.NET設計原則約束的時候,沒有解決方法 – nawfal

+0

@nawfal,請你詳細說明一下嗎? – series0ne