在回顧這裏的答案後,我有一點點玩弄自己,我已經出現了與下面的實現,它檢查運行時約束而不是編譯時間。
// 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。雖然這不提供編譯時間約束,但它確實提供了運行時約束,並且在約束中可以使用哪些類型的一些靈活性。
爲這些情況做的最好的事情是創建一個包裝類,或者採用更通用的東西(Object),並在構造函數中進行類型檢查。這很漂亮嗎?沒有。它會工作嗎?是。 – sybkar
@sybkar,你的意思就像我的回答? – series0ne