是否可以在特定类型上约束泛型方法?
我想写这样的东西:
public T GetValue<T>(string _attributeValue) where T : float, string
{
return default(T); // do some other stuff in reality
}
我主要是试图避免在方法中使用巨型switch
语句,或者如果指定了无效类型则必须抛出异常。
编辑:Ack。我知道string
不是值类型。我之前开始使用两种数字类型。遗憾。
答案 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