【问题标题】:Implementing Interface with static methods in C#在 C# 中使用静态方法实现接口
【发布时间】:2013-10-21 13:50:04
【问题描述】:

假设我有以下 ILAsm 代码:​​

    .class public interface abstract ITest
    {
        .field public static int32 counter

        .method public static void StaticMethod(string str)
        {
            ldarg.0
            call void [mscorlib]System.Console::WriteLine(string)
            ret
        }

        .method public virtual abstract void InstMethod(string) { }
    }

是否可以在 C# 中定义一个实现此ITest 接口的类?

我可以在 ILAsm 中实现这个接口:

    .class public TestImpl extends [mscorlib]System.Object implements ITest
    {
        .method public virtual void InstMethod(string str)
        {
            ldarg.1
            call void ITest::StaticMethod(string)
            ret
        }

        .method public specialname rtspecialname instance void .ctor()
        {
            ldarg.0
            call instance void .base::.ctor()
            ret
        }
    }

并在 C# 代码中成功使用实现的类:

        var testImpl = new TestImpl();
        testImpl.InstMethod("I'm static!"); 

但是用 C# 实现这个接口呢?

【问题讨论】:

  • 真的是界面吗? “.class”不是意味着它是一个类吗?如果它是一个接口,则表明 CLR 允许接口中的成员变量。这对我来说是一个新的。非常好的问题。
  • 真的是界面吗?因为它有方法实现。接口中不允许使用静态方法!!!
  • 你基本上想在这里建立一个抽象类。
  • @Derek 你不能从多个抽象类继承,所以它(有点)不同
  • 这是一个接口,因为使用了interface关键字,其实现存储在25(0x19) MethodImpl元数据表中。

标签: c# .net clr il


【解决方案1】:

令人惊讶的是(至少对我而言),您的 IL 代码编译和验证(为此使用 PEVerify)很好(假设您添加了一些 .assembly 指令)。

这是由 CLI 规范(§I.8.9.4 接口类型定义)支持的:

[…] 接口类型定义不应为接口类型的值(即实例字段)提供字段定义,尽管它可以声明静态字段。

[…] 接口类型定义可以定义和实现静态方法,因为静态 方法与接口类型本身相关联,而不是与该类型的任何值相关联。

但这样做不符合 CLS:

CLS 规则 19:符合 CLS 的接口不得定义静态方法,也不得定义字段。

您可以在 C# 中实现该接口。以下代码编译并运行良好:

class Test : ITest
{
    public void InstMethod(string s)
    { }
}

但您似乎无法从 C# 访问静态字段或静态方法。

【讨论】:

  • 确实令人惊讶。 CLR 有时是一种真正奇怪的野兽。
  • 确实,我认为即使通过反射也无法获得实现的静态:var m = new Test().GetType().GetMethods(BindingFlags.Static | BindingFlags.Public);
【解决方案2】:

这是对您的评论的回复:

我看不到即使通过反射也无法获得实现的静态:var m = new Test().GetType().GetMethods(BindingFlags.Static | BindingFlags.Public); – user2341923

记住,方法的声明类型是一个接口,所以你必须从接口类型中拉取方法定义。粗略地说,我认为这应该可行(使用添加的一些 linq 扩展)

var m = new Test().GetType().GetInterfaces().Where(
        i => i.IsAssignableFrom(
        typeof ITest)).First().GetMethods(
        BindingFlags.Static | BindingFlags.Public);

对于任何已实现的接口成员都是如此。实例或其他。

【讨论】:

    猜你喜欢
    • 2014-08-06
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 2017-04-26
    • 2013-01-12
    • 2016-10-06
    • 1970-01-01
    相关资源
    最近更新 更多