9

Consider the following Generic class:

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

This produces the following error:

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

Is there another way to constrain which types my generic class can use?

Also, can I constrain to multiple types?

E.G.

T can only be string, int or byte

4

3 回答 3

19
public class Custom<T> where T : string

是不允许的,因为唯一 T满足的是:string( stringis 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) { /*...*/ }
    }
}
于 2012-11-12T13:28:14.767 回答
2

根据我的经验,我会说我理解您为什么想要拥有,string并且int......因为通用基类的ID类型为 string 或 int

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

我们可以有一个约束class(reference object like string) 或struct(ValueType like int) 所以混合 string 和 int 是不可能的

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

于 2012-11-12T13:31:48.427 回答
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,这只是将继承限制在 this 上,并且也没有正确使用类型层次结构。就泛型的使用而言,这实际上是毫无意义的!

因此,我有另一种解决方案,它作为一种辅助方法来在运行时约束类型。这将对象从继承中释放出来,因此对类型层次结构没有影响。

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
    }

这现在允许对通用对象进行多种类型约束,即使类型是密封的等等。

“公共类 Custom where T : string ... 是不允许的,因为唯一符合条件的 T 是: string (字符串是密封的)——使它作为泛型毫无意义。”

是的,这是没有意义的,但是在某些情况下,您可能希望限制一个对象以允许,例如;字符串、StringBuilder 和 SecureString。虽然这不提供编译时约束,但它确实提供了运行时约束,以及可以在约束中使用哪些类型的一些灵活性。

于 2012-11-12T13:45:02.980 回答