2012-11-12 150 views
9

考虑下面的通用类:泛型类型参数的约束

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

这将产生以下错误:

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

有另一种方式来约束我的泛型类可以使用哪些类型?

此外,我可以限制到多种类型?

E.G.

T can only be string, int or byte

+0

为这些情况做的最好的事情是创建一个包装类,或者采用更通用的东西(Object),并在构造函数中进行类型检查。这很漂亮吗?没有。它会工作吗?是。 – sybkar

+0

@sybkar,你的意思就像我的回答? – series0ne

回答

16
public class Custom<T> where T : string 

是不允许的,因为只有T满足那就是:stringstringsealed) - 使得它相当无意义作为一种通用的。

Also, can I constrain to multiple types?

没有 - 除非你做的,而不是约束通过反射运行时(静态构造函数是做的一个方法 - 抛出一个异常,如果使用不当)

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

感谢您的回答......我有一点自己玩。如果你有一分钟​​,请看看我的答案,看看你的想法。任何建设性的批评是赞赏! :-) – series0ne

+0

“public class Custom where T:string ... is not allowed,because the only that that meets that is:string(string is sealed) - it makes it nothing pointless as a generic。” - 同意,字符串本身是毫无意义的,但可以说我想限制为String,StringBuilder和SecureString。这将是更有用的,但仍然是非法的,因为字符串是密封的:-( – series0ne

+0

@activwerx,这是不是泛型支持 –

2

从我的经验,我会说,我理解你为什么想有,stringint ......因为一个通用基类ID类型字符串或int

但是这是肯定的,这是不可能的。由于此MSDN的描述说: http://msdn.microsoft.com/en-us/library/d5x73970%28v=vs.80%29.aspx

我们可以有一个constraing class(如串参考对象)或struct(值类型如int) 那么混合字符串和INT将是不可能的

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

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从逻辑上思考,这只是限制继承,并且也没有正确使用类型层次结构。就泛型的使用而言,这实际上毫无意义!

因此,我有另一个解决方案作为一个辅助方法来限制运行时的类型。这从继承中释放了对象,因此对类型层次结构没有影响。

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

+4

不是一个伟大的使用泛型*或*继承,IMO .... –

+0

但是,在我们的选择受到C#和.NET设计原则约束的时候,没有解决方法 – nawfal

+0

@nawfal,请你详细说明一下吗? – series0ne