【问题标题】:using static methods of a constrained generic type C#使用受约束的泛型类型 C# 的静态方法
【发布时间】:2011-08-08 18:12:52
【问题描述】:

我有一个通用类:

public class Foo<T> where T: Interface
{

}

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

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

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

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

【问题讨论】:

  • 我很困惑,接口中不能存在静态方法。
  • 接口不能说它们的方法是静态的,你不能在接口中放置任何具体的代码。你的意思是抽象类而不是接口?
  • 是的,接口上不能有静态方法。
  • 您可以在接口中使用静态方法,但不能来自 C#。

标签: c# generics static constraints static-members


【解决方案1】:

您也许可以使用扩展方法。这种技术被命名为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);
}

【讨论】:

  • 好吧,我知道,复活一个旧线程和所有,但是:moooore 恶作剧我的包,muah hah hah hah!
【解决方案2】:

不,这是不可能的。甚至没有dynamic。 有通用约束(例如接口),但这仅适用于实例成员。您可以考虑将(参数)中的这些方法作为Func&lt;T&gt;/Action&lt;T&gt; 代表传递?

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

【讨论】:

  • 可怜的pquest将不得不回答你的答案:)
  • 顺便说一句,给定一个不满足 new() 约束的泛型类型 T,有没有办法强制静态类构造函数运行(如果它还没有运行)?有没有办法让一个类强制其父类的静态构造函数运行,如果它还没有运行,而不必硬编码父类的名称?
  • @supercat 不可靠,不。 ESP。随着 clr 4 中的 beforefieldinit 更改
  • @Marc Gravell:太糟糕了;否则,可以编写一个 DoSomething 方法,该方法可以在不显式使用反射的情况下调用 T 的最派生超类型的 DoSomething 方法,该方法“注册”了一个(使用静态注册列表)。但是,要使其工作,静态类必须在需要它们之前注册它们的方法。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

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

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

    所以,你有几个选择:

    1. 使用允许调用这些成员的语言(我认为 VB.NET 和 C++/CLI 允许这样做)。您可以编写一个可以在 C# 中使用的小型适配 shim;
    2. 要求为您提供此接口的人(甚至可能是您)不要在接口中使用静态成员。它们可以移动到单独的静态类中。该类甚至可以嵌套在接口中(如果语言允许的话),并且可以在 C# 中运行。

    【讨论】:

    • C# 不允许您在接口中定义静态方法。
    • 没错,甚至不叫它们....但是它们可以用其他语言定义。
    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-21
      相关资源
      最近更新 更多