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

时间:2011-08-08 18:12:53

标签: c# generics static constraints static-members

我有一个通用类:

public class Foo<T> where T: Interface
{

}

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

在构造函数中我希望能够基本上执行以下操作:

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

使用我上面发布的伪代码无法实现。是不是可以用这种方式调用这些静态方法?

5 个答案:

答案 0 :(得分:9)

您可以使用扩展方法。此技术已命名为pseudo-mixins。 虽然扩展方法实际上是静态的,但它们“假装”为实例方法,因此您仍然需要T的具体实例。

此外,如果您希望您的界面保留其作为自我记录“合同”的角色,指定您的T类应该具有哪些方法,这是一种作弊行为。 但是它们是类型安全的(如果你没有在范围内引入IBarExtensions,你的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);
}

答案 1 :(得分:4)

不,这是不可能的。甚至没有使用dynamic通用约束(例如接口),但仅适用于实例成员。您可以考虑将这些方法作为Func<T> / Action<T>委托传递给(参数)吗?

除此之外,你唯一的(也是不受欢迎的)选择就是反思。或者更好:重新考虑我们的方法。

答案 2 :(得分:1)

C#不允许您调用接口中定义的静态方法。它会发出poorly named错误消息:

  

如果您使用以允许接口中的静态成员的语言编写的库,并且您尝试从C#访问静态成员,也会出现CS0017。

如果C#允许,你可以使用接口名称而不是通用参数名称来调用它们:

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

所以,你有几个选择:

  1. 使用允许调用这些成员的语言(我认为 VB.NET和C ++ / CLI允许这样做)。您可以编写一个可以在C#;
  2. 中使用的小适配垫片
  3. 询问为您提供此界面的人(可能甚至是您)在界面中不使用静态成员。它们可以移动到单独的静态类。该类甚至可以嵌套在接口中(如果语言允许),它将在C#中起作用。

答案 3 :(得分:1)

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

答案 4 :(得分:0)

您还可以使用非静态方法作为调用静态方法的包装器。然后,非静态方法可以成为您界面的一部分。