是否可以在C#中调用泛型参数的方法?
在C++中,你可以从一个模板参数调用方法的,像这样:是否可以在C#中调用泛型参数的方法?
template<class T> class foo
{
T t;
t.foo();
}
但在C#中,看起来这是不可能的:
class foo<T>
{
T t;
public void foo() {
t.foo(); // Generates a compiler error
}
};
我想这大概是不可能的在C#中,是吗?
是的,如果你知道泛型类型的占位符T
实现了从基类或接口的成员,您可以使用where
条款约束型T
该基类或接口。
public interface IFooable
{
void Foo();
}
// ...
public class Foo<T> where T : IFooable
{
private T _t;
// ...
public void DoFoo()
{
_t.Foo(); // works because we constrain T to IFooable.
}
}
这使得一般类型占位符T
到被视为IFooable
。如果你做而不是限制泛型中的泛型类型占位符,那么它被限制为object
这意味着只有object
的成员对泛型可见(即,你只能看到对object
引用可见的成员,但调用任何被覆盖的成员将调用适当的覆盖)。
注:这是另外很重要的,因为事情像运算符重载(记住,符重载,未覆盖),所以如果你有这样的代码:
public bool SomeSuperEqualsChecker<T>(T one, T two)
{
return one == two;
}
这将始终使用object
的==
即使T
是string
。然而,如果我们有:
public bool SomeSuperEqualsChecker<T>(T one, T two)
{
// assume proper null checking exists...
return one.Equals(two);
}
这与string
因为Equals()
被覆盖,不超载正常工作。
所以,长和短只是记住一个无约束的通用占位符确实代表任何类型,但唯一可见的调用和操作是那些在object
上可见的调用和操作。
除了接口/基类的限制,也有一些其他方面的限制:
-
new()
- 意思是说,泛型类型的占位符必须有一个默认的构造函数 -
class
- 意思是说,泛型类型的占位符必须是引用类型 -
struct
- 意思是一般类型的占位符必须是一个值类型(枚举,原始的,结构等)
例如:
public class Foo<T> where T : new()
{
private T _t = new T(); // can only construct T if have new() constraint
}
public class ValueFoo<T> where T : struct
{
private T? _t; // to use nullable, T must be value type, constrains with struct
}
public class RefFoo<T> where T : class
{
private T _t = null; // can only assign type T to null if ref (or nullable val)
}
希望这会有所帮助。
您需要为您的方法添加type constraint。
public interface IFoo {
void Foo();
}
public class Foo<T> where T : IFoo {
T t;
public void foo() {
t.Foo(); // Generates a compiler error
}
}
如果您愿意接受泛型类型的约束,这意味着您的泛型类型必须受限于从某个基类派生或实现某个接口。
例子:
abstract class SomeBase
{
public abstract DoSomething();
}
// new() ensures that there is a default constructor to instantiate the class
class Foo<T> where T : SomeBase, new()
{
T t;
public Foo()
{
this.t = new T();
this.t.DoSomething(); // allowed because T must derive from SomeBase
}
}
您发现之间模板和仿制药的差异。尽管它们看起来很相似,但实际上却完全不同。
一个模板只需要为实际提供的类型参数是正确的;如果你提供一个没有foo方法的T,那么编译失败;如果仅提供具有foo的类型参数,则编译成功。
相比之下,任何可能的T都必须正确对应于。由于我们没有证据表明每个可能的T都会有一个foo的方法,所以通用是非法的。
+1很好的答案! – Yuck 2011-12-23 22:23:49