使用c#约束泛型类型的静态方法

本文关键字:静态方法 泛型类型 约束 使用 | 更新日期: 2023-09-27 18:04:45

我有一个通用类:

public class Foo<T> where T: Interface
{
}

T被强制实现的接口在其内部定义了两个静态方法。

在构造函数中,我希望能够基本做到以下几点:

public Foo()
{
   value1 = T.staticmethod1();
   value2 = T.staticmethod2();
}

这不能用我上面发布的伪代码来完成。难道不能以这种方式调用这些静态方法吗?

使用c#约束泛型类型的静态方法

您可以使用扩展方法。这种技术被命名为伪混合。尽管扩展方法实际上是静态的,但它们"假装"是实例方法,因此您仍然需要t的具体实例。

同样,这也是一种欺骗,如果你想让你的接口保留它作为一个自文档的"契约"的角色,指定你的T类应该有什么方法。然而,它们是类型安全的(如果不将ibareextensions引入作用域,您的Foo类将无法编译)

//our interface
public interface IBar {}
// the two static methods are define as extension methods
public static class IBarExtensions {
    public static string someMethod1(this IBar self) {
        return "my initialization 1";
    }
    public static string someMethod2(this IBar self) {
        return "my initialization 2";
    }
}
public class Foo<T> where T : IBar, new()
{
    public string value1 {get; private set;}
    public string value2 {get; private set;}
    public Foo() {
        T t = new T(); // we can do this because of the "new()" constraint
                           // in the class definition
                           // Alternatively we could pass an instance of T in
                           // the constructor 
                           // public Foo(T t)
        value1 = t.someMethod1();
        value2 = t.someMethod2();       
    }
}
测试

public class TestBar : IBar {}
void Main()
{
    var c = new TestBar();
    var t = new Foo<TestBar>();
    Console.WriteLine(t.value1);
}

不,不可能。即使是dynamic也不行。有泛型约束(例如接口),但这只适用于实例成员。你可以考虑传递这些方法(参数)作为Func<T>/Action<T>委托?

除此之外,你唯一的(也是不希望的)选择就是反射。或者更好的做法是:重新考虑我们在这里的做法。

不能使用受约束泛型类型形参的静态成员,因为特定类型中是否存在静态成员并不能说明派生类型是否具有与该名称兼容的成员。假设类型"Foo"有一个静态函数Wowzo()返回Int32,类型DerivedFoo1有一个不同的静态函数Wowzo()也返回Int32,类型DerivedFoo2(派生自Foo)有一个静态成员Wowzo()返回String,类型DerivedFoo3有一个嵌套类Wowzo。如果T是一个类型参数,约束为Foo的后代,那么T.Wowzo是什么?

c#不允许调用接口中定义的静态方法。它发出一个命名不当的错误消息:

CS0017也会发生,如果您使用的是用允许在接口中使用静态成员的语言编写的库,并且您尝试从c#访问静态成员。

如果c#允许的话,你可以使用接口名而不是泛型参数名来调用它们:

// doesn't work:
public Foo() {
  value1 = Interface.staticmethod1();
  value2 = Interface.staticmethod2(); 
} 

所以,你有几个选项:

    使用一种允许调用这些成员的语言(我认为 VB)。. NET和c++/CLI允许这样做)。你可以写一个小的适配器,你可以从c#使用;
  1. 要求为您提供此接口的人(可能甚至是您)不要在接口中使用静态成员。它们可以移动到单独的静态类中。类甚至可以嵌套在接口中(如果语言允许的话),它将在c#中工作。

您也可以使用非静态方法作为包装器调用静态方法。非静态方法可以成为接口的一部分。