没有C#(或.NET)为什么要允许我们把一个静态/共享方法的接口里面?(Why shouldn

2019-06-24 12:19发布

没有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
}

Answer 1:

接口的想法是代表一个合同,而不是实现。

我不记得随便IL实际上是否确实允许在接口的实现静态方法-我偷偷摸摸怀疑它-但有些muddies概念。

我可以看到你的观点 - 它有时是有用知道什么辅助方法,它们有一个接口连接(和扩展方法是特别重要存在),但我个人希望把那些在一个单独的类,无论如何,只是为了保持精神模型干净。



Answer 2:

我碰到的这个好几次,做了一些研究。 不幸的是,IL实际上支持这一点。 我得到这个很沮丧,我写了一篇博客文章了。 你可以找到它在这里 。



Answer 3:

为了您的目的,这将是更好的去耦插件加载实现插件接口:这会让你的设计更耦合,并且更有凝聚力(从而减少复杂性)。

至于“接口静态方法”,看到这个 。

而作为一个旁注:你真的不想去创造另一个插件架构:看一看MEF 。



Answer 4:

检查出的接口来实现的静态方法我的博客文章(抱歉无耻的自我参考)

[除去破碎连结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);
}

智能感知(VS)不能按预期在这里工作。 它认识到静态方法作为接口的实例方法和代码(如果按照智能感知提示)看起来一切为了就好像要编译。 C#编译器(MS C#)不编译的代码作为C#不suppport上实现的接口的静态方法,且可从C#仅通过反射来调用。

我还没有测试其它的IDE如SharpDevelop的...所以不知道尚未将如何应对这种情况。



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



Answer 6:

静态方法与它们所宣称和覆盖不相关的类型有关。 如果你能够在静态方法附加到一个界面中,你将不得不通过接口本身,如引用它ITaskPlugin.GetPlugins(...)

你想要做的要么是:

1)把你方法的抽象基类,接口没有设计容纳实现代码,或

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



Answer 7:

一个接口的目的是声明一个对象的接口,通过它可以被访问。 由于这样的事实,这是它的唯一目的,那就没有意义的允许代码被放置在一个接口。 如果你仍然想添加一些代码的接口,你可以使用扩展方法。



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