C#.NET中的泛型类型参数约束

时间:2012-11-12 13:24:30

标签: c# .net generics constraints

考虑以下Generic类:

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

这会产生以下错误:

  

'string'不是有效的约束。用作约束的类型必须   是一个接口,一个非密封类或一个类型参数。

是否有另一种方法可以限制我的泛型类可以使用哪些类型?

另外,我可以约束多种类型吗?

E.G。

  

T只能是字符串,整数或字节

3 个答案:

答案 0 :(得分:16)

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

答案 1 :(得分:2)

根据我的经验,我会说我明白为什么你想拥有,stringint ...因为类型为 ID 的通用基类string或int

但可以肯定的是,这是不可能的。正如这篇msdn描述所说: http://msdn.microsoft.com/en-us/library/d5x73970%28v=vs.80%29.aspx

我们可以有一个约束class(像字符串这样的引用对象)或struct(ValueType就像int) 所以混合字符串和int是不可能的

注意:字符串的错误有意义,因为字符串是密封的,所以它不必像通用一样 - 字符串ID 是我们需要的

答案 2 :(得分: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");
        }
    }
}

现在我从我的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,StringBuilder和SecureString。虽然这不提供编译时约束,但它确实提供了运行时约束,并且可以在约束中使用哪些类型的灵活性。