簡體   English   中英

C#.NET中的泛型類型參數約束

[英]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滿足那就是: stringstringsealed ) -使得它相當無意義作為一種通用的。

另外,我可以約束多種類型嗎?

否 - 除非你在運行時通過反射而不是在約束中執行此操作(靜態構造函數是一種方法 - 如果使用不正確則拋出異常)

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) { /*...*/ }
    }
}

根據我的經驗,我會說我理解為什么你想擁有, stringint ...因為一個通用的基類具有類型為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM