是否可以在C#中调用泛型参数的方法?

Ste*_*oss 3 c#

在C++中,您可以从模板参数调用方法,如下所示:

template<class T> class foo
{
  T t;
  t.foo();
}
Run Code Online (Sandbox Code Playgroud)

但在C#中,看起来这是不可能的:

class foo<T>
{
  T t;
  public void foo() { 
    t.foo(); // Generates a compiler error
  }
};
Run Code Online (Sandbox Code Playgroud)

我想这在C#中可能是不可能的,是吗?

Eri*_*ert 11

您已经发现了模板泛型之间的区别.虽然它们看起来很相似但实际上却完全不同.

模板只需要对实际提供的类型参数是正确的; 如果你提供一个没有方法foo的T,那么编译失败; 如果只提供具有foo的类型参数,则编译成功.

相比之下,通用必须对任何可能的T都是正确的.由于我们没有证据表明每个可能的T都有方法foo,因此通用是非法的.


Jam*_*are 9

是的,如果您知道泛型类型占位符T实现了基类或接口的成员,则可以T使用where子句将类型约束到该基类或接口.

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.
    }
}
Run Code Online (Sandbox Code Playgroud)

这使得泛型类型占位符T可以被视为IFooable.如果你没有约束泛型中的泛型类型占位符,那么它被约束到object只有那些object成员对泛型可见(也就是说,你只看到object引用可见的成员,但调用任何被覆盖的成员将调用适当的覆盖).

注意:这是另外重要的,因为像运算符重载(请记住运算符被重载,而不是重写),所以如果您有这样的代码:

public bool SomeSuperEqualsChecker<T>(T one, T two)
{
    return one == two;
}
Run Code Online (Sandbox Code Playgroud)

这将始终使用object==即使Tstring.但是,如果我们有:

public bool SomeSuperEqualsChecker<T>(T one, T two)
{
    // assume proper null checking exists...
    return one.Equals(two);
}
Run Code Online (Sandbox Code Playgroud)

这个WOULD按预期工作,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)
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.