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

发布于 2024-07-25 14:45:27 字数 2982 浏览 6 评论 0原文

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

似乎与 为什么我们可以重复接口/抽象类中没有共享(静态)函数/方法?,但我的想法有点不同,;我只是想为我的插件(接口)放置一个助手,

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
}

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

Seemingly duplicate from Why we can not have Shared(static) function/methods in an interface/abstract class?, but my idea is a bit different,;I just want to put a helper for my plugins(interface)

Shouldn't C# at least allow this idea?

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
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

メ斷腸人バ 2024-08-01 14:45:27

接口的思想是代表契约,而不是实现。

我不记得 IL 实际上是否允许在接口中实现静态方法 - 我偷偷怀疑它确实如此 - 但这在某种程度上使这个概念变得混乱。

我可以理解你的观点 - 有时了解哪些可用的辅助方法与接口连接(并且扩展方法在那里特别相关)很有用,但我个人希望无论如何将它们放在一个单独的类中,只是为了保持心理状态模型干净。

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.

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.

穿透光 2024-08-01 14:45:27

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

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.

死开点丶别碍眼 2024-08-01 14:45:27

出于您的目的,最好将插件接口与插件加载器实现解耦:这将使您的设计耦合性更低,内聚性更强(从而降低复杂性)。

至于“接口中的静态方法”,请参见这个

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

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.

源来凯始玺欢你 2024-08-01 14:45:27

查看我关于接口中实现的静态方法的博客文章(抱歉无耻的自我引用)

[删除了损坏的链接http://...]

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

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

[...]

使用 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
 } 
} 

此代码然后可以称为

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) 在这里无法按预期工作。 它将静态方法识别为接口的实例方法,并且代码(如果遵循智能感知提示)看起来一切都按顺序进行,就好像要编译一样。 C# 编译器 (MS C#) 不会编译代码,因为 C# 不支持接口上实现的静态方法,并且只能通过反射从 C# 调用。

我还没有测试过其他 IDE,例如 SharpDevelop……所以还不知道它将如何处理这种情况。

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

[removed broken link http:/... ]

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

Edit:
I pasted a cached version below I found:

[...]

Use ILAsm to compile the following:

.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.

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

ぇ气 2024-08-01 14:45:27

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

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

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.

梦途 2024-08-01 14:45:27

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

您想要做的是:

1)将您的方法放入抽象基类中,因为接口并非旨在保存实现代码,或者

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

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(...)

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

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.

够钟 2024-08-01 14:45:27

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文