考虑以下Generic类:
public class Custom<T> where T : string
{
}
这会产生以下错误:
'string'不是有效的约束。用作约束的类型必须 是一个接口,一个非密封类或一个类型参数。
是否有另一种方法可以限制我的泛型类可以使用哪些类型?
另外,我可以约束多种类型吗?
E.G。
T只能是字符串,整数或字节
答案 0 :(得分:16)
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) { /*...*/ }
}
}
答案 1 :(得分:2)
根据我的经验,我会说我明白为什么你想拥有,string
和int
...因为类型为 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。虽然这不提供编译时约束,但它确实提供了运行时约束,并且可以在约束中使用哪些类型的灵活性。