[英]Generic Type Parameter constraints in C# .NET
考慮以下Generic類:
public class Custom<T> where T : string
{
}
這會產生以下錯誤:
'string'不是有效的約束。 用作約束的類型必須是接口,非密封類或類型參數。
是否有另一種方法來約束我的泛型類可以使用哪些類型?
另外,我可以約束多種類型嗎?
例如
T只能是string,int或byte
public class Custom<T> where T : string
是不允許的,因為只有 T
滿足那就是: string
( string
被sealed
) -使得它相當無意義作為一種通用的。
另外,我可以約束多種類型嗎?
否 - 除非你在運行時通過反射而不是在約束中執行此操作(靜態構造函數是一種方法 - 如果使用不正確則拋出異常)
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) { /*...*/ }
}
}
根據我的經驗,我會說我理解為什么你想擁有, string
和int
...因為一個通用的基類具有類型為string或int的ID
但可以肯定的是,這是不可能的。 正如這篇msdn描述所說: http : //msdn.microsoft.com/en-us/library/d5x73970%28v=vs.80%29.aspx
我們可以有一個約束class
(像字符串這樣的引用對象)或者struct
(像int這樣的ValueType)因此混合字符串和int是不可能的
注意:字符串的錯誤是有意義的,因為字符串是密封的,所以它不必像通用一樣 - 字符串ID是我們需要的
在回顧了這里的答案,並對自己進行了一些調整后,我提出了以下實現,它在運行時而不是編譯時檢查約束。
// 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");
}
}
}
現在我從我的Custom類繼承了這個...
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其中T:string ...是不允許的,因為唯一符合它的是:string(字符串是密封的) - 使它像通用一樣毫無意義。”
是的,這是毫無意義的,但在某些情況下,您可能希望將對象限制為允許,例如; String,StringBuilder和SecureString。 雖然這不提供編譯時約束,但它確實提供了運行時約束,並且可以在約束中使用哪些類型的一些靈活性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.