代码之家  ›  专栏  ›  技术社区  ›  Adam Lear

将类型约束到特定类型

  •  3
  • Adam Lear  · 技术社区  · 14 年前

    是否可以将泛型方法约束到特定类型上?

    我想这样写:

    public T GetValue<T>(string _attributeValue) where T : float, string
    {
        return default(T); // do some other stuff in reality
    }
    

    switch

    编辑:确认。我就知道 string

    4 回复  |  直到 14 年前
        1
  •  5
  •   LBushkin    14 年前

    不能使用泛型约束来表示您感兴趣的限制。 泛型并不是用来表示基于不相交类型的变体,而是用来表示在类型层次结构(或实现某些接口的层次结构)上统一的变体。

    不过,你还有一些选择。你选择哪一个取决于你想做的事情的确切性质。

    使用不同的命名方法来表示每个操作。 我倾向于使用这种方法,当每种方法都在做不同的事情时。您可能会认为,从方法返回不同类型的值本质上是一种不同的操作,应该有自己独特的名称。

    float GetFloat(string attrName) { }
    string GetString(string attrName) { }
    

    提供“默认值”以允许推断类型。 在许多按名称要求值的设计中,提供默认值很有用。这允许您使用重载来区分要调用的方法(基于默认值的类型)。不幸的是,这种方法非常脆弱,并且在将文本值传递给接受数字原语(int vs.uint vs.long)的重载时很容易中断。

    float GetValue(string attrName, float defaultValue) { ... }
    string GetValue(string attrName, string defaultValue) { ... }
    

    就我个人而言,我发现这种情况很难看,而且违反了泛型的精神——泛型应该将功能统一到实现某些接口的层次结构或一组类型上。但是,在某些情况下,这样做是有意义的(假设某个特定类型不受支持)。这种方法的另一个问题是不能从任何参数推断泛型方法的签名,因此在调用泛型方法时必须指定所需的类型。。。在这一点上(从语法的角度来看)并不比使用不同的方法名好多少。

    T GetValue<T>( string attrName )
    {
       if( typeof(T) != typeof(string) ||
           typeof(T) != typeof(float) )
           throw new NotSupportedException();
       return default(T); 
    }
    
    // call it by specifying the type expected...
    float f = GetValue<float>(attrName);
    string s = GetValue<string>(attrName);
    

    使用out参数而不是返回值。 这种方法工作得很好,但它失去了能够调用方法并对返回值执行操作的简洁语法,因为首先必须声明要填充的变量。

    void GetValue( string attrName, out float value )
    void GetValue( string attrName, out string value )
    
    // example of usage:
    float f;
    GetValue( attrName, out f );
    string s;
    GetValue( attrName, out s );
    
        2
  •  2
  •   Steven    14 年前

    这是不可能做到的编译时支持。您可以在静态构造函数中执行此检查,并在方法体本身中抛出异常(在类型上定义T的情况下)或(在您的情况下),但在这种情况下,这将是一个运行时验证。

        3
  •  2
  •   Justin Niessner    14 年前

    不,不可能。

    字符串是引用类型,而不是值类型。

    public T GetValue<T>(string _attributeValue) where T : struct
    

    根据您在方法中实际执行的操作,可能有各种方法来实现您的目标(switch/case除外)。考虑把你的例子改得更有意义一点。。。

    另一种选择可能是将方法私有化,并提供特定的公共包装器:

    private T GetValue<T>(string _attributeValue) where T : struct
    {
        return default(T);
    }
    
    public float GetFloatValue(string _attributeValue)
    {
        return GetValue<float>(_attributeValue);
    }
    
    public int GetIntValue(string _attributeValue)
    {
        return GetValue<int>(_attributeValue);
    }
    

    这将允许您将类的公共成员约束到所需的类型,但仍然在内部使用泛型代码,这样您就不必重复自己。

        4
  •  1
  •   Nix    14 年前

     where T: struct