将类型约束为特定类型

时间:2010-08-04 15:08:22

标签: c# .net-2.0

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

我想写这样的东西:

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

我主要是试图避免在方法中使用巨型switch语句,或者如果指定了无效类型则必须抛出异常。

编辑:Ack。我知道string不是值类型。我之前开始使用两种数字类型。遗憾。

4 个答案:

答案 0 :(得分:5)

您不能使用通用约束来表达您感兴趣的限制。泛型并不是要表达基于不相交类型的变体 - 它们是为了表达统一的变体。类型的层次结构(或实现某些接口的那些)。

但是,您有一些替代选择。你选择哪个取决于你想要做的事情的确切性质。

使用不同命名的方法来表达每个操作。当每个方法真正做出不同的事情时,我倾向于使用这种方法。您可能会争辩说,从方法返回不同类型的值本质上是一种不同的操作,并且应该拥有自己唯一的名称。

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

提供“默认值”以允许推断类型。在许多通过名称请求值的设计中,提供默认值很有用。这可以允许您使用重载来区分要调用的方法(基于默认值的类型)。不幸的是,这种方法非常脆弱 - 在将文字值传递给接受数字原语的重载(int与uint与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 );

答案 1 :(得分:2)

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

答案 2 :(得分:2)

不,这是不可能的。

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

最接近的是约束所有值类型(减去Nullable类型):

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

根据您在方法中实际执行的操作,可能有多种方法可以实现您的目标(除了切换/案例)。考虑将您的示例更改为更有意义......

另一个选项也可能是将您的方法设为私有,并提供特定的公共包装:

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);
}

这将允许您将类的公共成员约束为所需类型,但仍在内部使用通用代码,因此您不必重复自己。

答案 3 :(得分:1)

不,您不能指定一系列类型。如果你想要你可以做的所有原语(我知道字符串不包括在内)

 where T: struct