为什么C#(或.NET)不允许我们在接口中放置静态/共享方法?

时间:2022-09-02 12:02:18

Why shouldn't C#(or .NET) allow us to put a static/shared method inside an interface?

为什么C#(或.NET)不允许我们在接口中放置静态/共享方法?

seemingly duplicate from here. but my idea is a bit different one, I just want to put a helper for my plugins(interface)

看似从这里重复。但我的想法有点不同,我只是想为我的插件(接口)添加一个帮助器

shouldn't C# at least allow this idea?

不应该C#至少允许这个想法吗?

namespace MycComponent
{

    public interface ITaskPlugin : ITaskInfo
    {
        string Description { get; }
        string MenuTree { get; }
        string MenuCaption { get; }

        void ShowTask(Form parentForm);
        void ShowTask(Form parentForm, Dictionary<string, object> pkColumns);

        ShowTaskNewDelegate ShowTaskNew { set; get; }
        ShowTaskOpenDelegate ShowTaskOpen { set; get; }        

        // would not compile with this:
        public static Dictionary<string, ITaskPlugin> GetPlugins(string directory)
        {

            var l = new Dictionary<string, ITaskPlugin>();

            foreach (string file in Directory.GetFiles(directory))
            {
                var fileInfo = new FileInfo(file);   
                if (fileInfo.Extension.Equals(".dll"))
                {
                    Assembly asm = Assembly.LoadFile(file);       
                    foreach (Type asmType in asm.GetTypes())
                    {

                        if (asmType.GetInterface("MycComponent.ITaskPlugin") != null)
                        {
                            var plugIn = (ITaskPlugin)Activator.CreateInstance(asmType);
                            l.Add(plugIn.TaskName, plugIn);
                        }

                    }


                }
            }

            return l;
        } // GetPlugins.  would not compile inside an interface
    }



    /* because of the error above, I am compelled to 
       put the helper method in a new class. a bit overkill when the method should
       be closely coupled to what it is implementing */
    public static class ITaskPluginHelper
    {
        public static Dictionary<string, ITaskPlugin> GetPlugins(string directory)
        {

            var l = new Dictionary<string, ITaskPlugin>();

            foreach (string file in Directory.GetFiles(directory))
            {
                var fileInfo = new FileInfo(file);   
                if (fileInfo.Extension.Equals(".dll"))
                {
                    Assembly asm = Assembly.LoadFile(file);       
                    foreach (Type asmType in asm.GetTypes())
                    {

                        if (asmType.GetInterface("MycComponent.ITaskPlugin") != null)
                        {
                            var plugIn = (ITaskPlugin)Activator.CreateInstance(asmType);
                            l.Add(plugIn.TaskName, plugIn);
                        }

                    }


                }
            }

            return l;
        } // GetPlugins    
    } // ITaskPluginHelper
}

7 个解决方案

#1


The idea of an interface is to represent a contract, not implementation.

接口的概念是代表合同,而不是实现。

I can't remember offhand whether IL actually does allow static methods with implementations in interfaces - I've a sneaky suspicion that it does - but that muddies the concept somewhat.

我不记得IL是否实际上允许静态方法在接口中实现 - 我有一种偷偷摸摸的怀疑它确实存在 - 但这有点混淆了这个概念。

I can see your point - it's sometimes useful to know what helper methods are available which are connected with an interface (and extension methods are particularly relevant there) but I would personally want to put those in a separate class anyway, just to keep the mental model clean.

我可以看到你的观点 - 知道哪些辅助方法与接口连接有时很有用(扩展方法在那里特别相关)但我个人想要将它们放在一个单独的类中,只是为了保持精神状态。模特干净。

#2


I've run into this several times and did some research. The sad part is, IL actually supports this. I got so frustrated with this I wrote a blog post about it. You can find it here.

我已经多次遇到这种情况并做了一些研究。可悲的是,IL实际上支持这一点。我对此感到非常沮丧,我写了一篇关于它的博客文章。你可以在这里找到它。

#3


For your purpose, it will be much better to decouple plugin interface from plugin loader implementation: this will make your design much less coupled and more cohesive (thus reducing complexity).

为了您的目的,将插件接口与插件加载器实现分离会更好:这将使您的设计更少耦合和更具凝聚力(从而降低复杂性)。

As for "static methods in interface", see this.

至于“界面中的静态方法”,请参阅此内容。

And as a sidenote: you don't really want to invent yet another plugin architecture: take a look at MEF.

作为旁注:你真的不想发明另一个插件架构:看看MEF。

#4


Check out my blog entry on static methods implemented in interfaces (sorry for the shameless self reference)

查看我的博客条目,了解接口中实现的静态方法(对于无耻的自我引用感到抱歉)

[removed broken link http:/... ]

[删除了断开的链接http:/ ...]

dotnetjunkies site is poked by totaldevpro ... so the google cached version is the only one available

dotnetjunkies网站被totaldevpro戳了...所以google缓存版本是唯一可用的版本

Edit: I pasted a cached version below I found:

编辑:我在下面粘贴了一个缓存版本,我发现:

[...]

Use ILAsm to compile the following:

使用ILAsm编译以下内容:

.assembly extern mscorlib {
 .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         
 .ver 2:0:0:0
}

 .assembly MaLio.StaticInterface{
 .hash algorithm 0x00008004
 .ver 0:1:0:0
}

.module MaLio.StaticInterface.dll
.imagebase 0x00400000
.file alignment 0x00001000
.stackreserve 0x00100000
.subsystem 0x0003      
.corflags 0x00000001   

.class interface public abstract auto ansi MaLio.IMyInterface {

 .method public hidebysig newslot abstract virtual instance void  DoInstanceWork() cil managed  {
 } 

 .method public hidebysig static void  DoStaticWork() cil managed  {
     ldstr      "Static"
     call       void [mscorlib]System.Console::WriteLine(string)
     ret
 } 
} 

.class public auto ansi beforefieldinit MaLio.MyClass extends [mscorlib]System.Object implements MaLio.IMyInterface {

 .method public hidebysig newslot virtual final instance void  DoInstanceWork() cil managed  {
     ldstr      "Instance"
     call       void [mscorlib]System.Console::WriteLine(string)
     ret
 } 

 .method public hidebysig specialname rtspecialname instance void  .ctor() cil managed {
     ldarg.0
     call       instance void [mscorlib]System.Object::.ctor()
     ret
 } 
} 

This code then can be called

然后可以调用此代码

System.Type myInterface = typeof(MaLio.IMyInterface);
// show that we really are dealing with an interface 
if (myInterface.IsInterface) {
   System.Reflection.MethodInfo staticMethod = myInterface.GetMethod("DoStaticWork");
   staticMethod.Invoke(null, null);
}

Intellisense (VS) does not work here as expected. It recognized the static method as an instance method of the interface, and the code (if following the intellisense prompts) looks all in order as if it were going to compile. The C# compiler (MS C#) does not compile the code as C# does not suppport implemented static methods on interfaces, and can from C# only be invoked via reflection.

智能感知(VS)在这里不能按预期工作。它将静态方法识别为接口的实例方法,并且代码(如果遵循智能感知提示)看起来就像它要编译一样。 C#编译器(MS C#)不编译代码,因为C#不支持在接口上实现静态方法,并且只能通过反射调用C#。

I have not tested with other IDE's such as SharpDevelop ... so have no idea as yet how it would deal with this situation.

我还没有测试过其他IDE,比如SharpDevelop ......所以还不知道它是如何处理这种情况的。

#5


An interface is just that, an interface. It isn't meant to be used to describe behavior. When a class implements an interface, the class just says "I promise that I provide methods/events/etc with these signatures".

接口只是一个接口。它并不意味着用于描述行为。当一个类实现一个接口时,该类只是说“我保证我提供带有这些签名的方法/事件/等”。

What you want is an interface without the static method and an abstract base class that implements the interface and the static method. Then other classes can inherit from the base class and change the interface's method implementations. But even this is a questionable design.

你想要的是没有静态方法的接口和实现接口和静态方法的抽象基类。然后其他类可以从基类继承并更改接口的方法实现。但即使这是一个值得怀疑的设计。

#6


static methods are associated with the type in which they are declared and not relevant for overriding. If you were able to attach a static method to an interface, you would have to reference it via the interface itself, e.g. ITaskPlugin.GetPlugins(...)

静态方法与声明它们的类型相关联,与覆盖无关。如果您能够将静态方法附加到接口,则必须通过接口本身引用它,例如ITaskPlugin.GetPlugins(...)

What you want to do is either:

你想要做的是:

1) Put your method in an abstract base class, as interfaces are not designed to hold implementation code, or

1)将您的方法放在抽象基类中,因为接口不是为了保存实现代码而设计的,或者

2) Create an extension method which applies to the interface and then you'll have access to it without having to use a base class.

2)创建一个适用于接口的扩展方法,然后您就可以访问它而无需使用基类。

#7


An interface's purpose is to declare an object's interface through which it can be accessed. Due to the fact that this is its sole purpose, it would not make sense to allow code being placed in an interface. If you still want to add some code to an interface, you could use extension methods.

接口的目的是声明一个对象的接口,通过它可以访问它。由于这是它的唯一目的,因此将代码放在接口中是没有意义的。如果您仍想在界面中添加一些代码,可以使用扩展方法。

#1


The idea of an interface is to represent a contract, not implementation.

接口的概念是代表合同,而不是实现。

I can't remember offhand whether IL actually does allow static methods with implementations in interfaces - I've a sneaky suspicion that it does - but that muddies the concept somewhat.

我不记得IL是否实际上允许静态方法在接口中实现 - 我有一种偷偷摸摸的怀疑它确实存在 - 但这有点混淆了这个概念。

I can see your point - it's sometimes useful to know what helper methods are available which are connected with an interface (and extension methods are particularly relevant there) but I would personally want to put those in a separate class anyway, just to keep the mental model clean.

我可以看到你的观点 - 知道哪些辅助方法与接口连接有时很有用(扩展方法在那里特别相关)但我个人想要将它们放在一个单独的类中,只是为了保持精神状态。模特干净。

#2


I've run into this several times and did some research. The sad part is, IL actually supports this. I got so frustrated with this I wrote a blog post about it. You can find it here.

我已经多次遇到这种情况并做了一些研究。可悲的是,IL实际上支持这一点。我对此感到非常沮丧,我写了一篇关于它的博客文章。你可以在这里找到它。

#3


For your purpose, it will be much better to decouple plugin interface from plugin loader implementation: this will make your design much less coupled and more cohesive (thus reducing complexity).

为了您的目的,将插件接口与插件加载器实现分离会更好:这将使您的设计更少耦合和更具凝聚力(从而降低复杂性)。

As for "static methods in interface", see this.

至于“界面中的静态方法”,请参阅此内容。

And as a sidenote: you don't really want to invent yet another plugin architecture: take a look at MEF.

作为旁注:你真的不想发明另一个插件架构:看看MEF。

#4


Check out my blog entry on static methods implemented in interfaces (sorry for the shameless self reference)

查看我的博客条目,了解接口中实现的静态方法(对于无耻的自我引用感到抱歉)

[removed broken link http:/... ]

[删除了断开的链接http:/ ...]

dotnetjunkies site is poked by totaldevpro ... so the google cached version is the only one available

dotnetjunkies网站被totaldevpro戳了...所以google缓存版本是唯一可用的版本

Edit: I pasted a cached version below I found:

编辑:我在下面粘贴了一个缓存版本,我发现:

[...]

Use ILAsm to compile the following:

使用ILAsm编译以下内容:

.assembly extern mscorlib {
 .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         
 .ver 2:0:0:0
}

 .assembly MaLio.StaticInterface{
 .hash algorithm 0x00008004
 .ver 0:1:0:0
}

.module MaLio.StaticInterface.dll
.imagebase 0x00400000
.file alignment 0x00001000
.stackreserve 0x00100000
.subsystem 0x0003      
.corflags 0x00000001   

.class interface public abstract auto ansi MaLio.IMyInterface {

 .method public hidebysig newslot abstract virtual instance void  DoInstanceWork() cil managed  {
 } 

 .method public hidebysig static void  DoStaticWork() cil managed  {
     ldstr      "Static"
     call       void [mscorlib]System.Console::WriteLine(string)
     ret
 } 
} 

.class public auto ansi beforefieldinit MaLio.MyClass extends [mscorlib]System.Object implements MaLio.IMyInterface {

 .method public hidebysig newslot virtual final instance void  DoInstanceWork() cil managed  {
     ldstr      "Instance"
     call       void [mscorlib]System.Console::WriteLine(string)
     ret
 } 

 .method public hidebysig specialname rtspecialname instance void  .ctor() cil managed {
     ldarg.0
     call       instance void [mscorlib]System.Object::.ctor()
     ret
 } 
} 

This code then can be called

然后可以调用此代码

System.Type myInterface = typeof(MaLio.IMyInterface);
// show that we really are dealing with an interface 
if (myInterface.IsInterface) {
   System.Reflection.MethodInfo staticMethod = myInterface.GetMethod("DoStaticWork");
   staticMethod.Invoke(null, null);
}

Intellisense (VS) does not work here as expected. It recognized the static method as an instance method of the interface, and the code (if following the intellisense prompts) looks all in order as if it were going to compile. The C# compiler (MS C#) does not compile the code as C# does not suppport implemented static methods on interfaces, and can from C# only be invoked via reflection.

智能感知(VS)在这里不能按预期工作。它将静态方法识别为接口的实例方法,并且代码(如果遵循智能感知提示)看起来就像它要编译一样。 C#编译器(MS C#)不编译代码,因为C#不支持在接口上实现静态方法,并且只能通过反射调用C#。

I have not tested with other IDE's such as SharpDevelop ... so have no idea as yet how it would deal with this situation.

我还没有测试过其他IDE,比如SharpDevelop ......所以还不知道它是如何处理这种情况的。

#5


An interface is just that, an interface. It isn't meant to be used to describe behavior. When a class implements an interface, the class just says "I promise that I provide methods/events/etc with these signatures".

接口只是一个接口。它并不意味着用于描述行为。当一个类实现一个接口时,该类只是说“我保证我提供带有这些签名的方法/事件/等”。

What you want is an interface without the static method and an abstract base class that implements the interface and the static method. Then other classes can inherit from the base class and change the interface's method implementations. But even this is a questionable design.

你想要的是没有静态方法的接口和实现接口和静态方法的抽象基类。然后其他类可以从基类继承并更改接口的方法实现。但即使这是一个值得怀疑的设计。

#6


static methods are associated with the type in which they are declared and not relevant for overriding. If you were able to attach a static method to an interface, you would have to reference it via the interface itself, e.g. ITaskPlugin.GetPlugins(...)

静态方法与声明它们的类型相关联,与覆盖无关。如果您能够将静态方法附加到接口,则必须通过接口本身引用它,例如ITaskPlugin.GetPlugins(...)

What you want to do is either:

你想要做的是:

1) Put your method in an abstract base class, as interfaces are not designed to hold implementation code, or

1)将您的方法放在抽象基类中,因为接口不是为了保存实现代码而设计的,或者

2) Create an extension method which applies to the interface and then you'll have access to it without having to use a base class.

2)创建一个适用于接口的扩展方法,然后您就可以访问它而无需使用基类。

#7


An interface's purpose is to declare an object's interface through which it can be accessed. Due to the fact that this is its sole purpose, it would not make sense to allow code being placed in an interface. If you still want to add some code to an interface, you could use extension methods.

接口的目的是声明一个对象的接口,通过它可以访问它。由于这是它的唯一目的,因此将代码放在接口中是没有意义的。如果您仍想在界面中添加一些代码,可以使用扩展方法。