繁体   English   中英

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

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

为什么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
}

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

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

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

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

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

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

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

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

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

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

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

[...]

使用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#不支持在接口上实现静态方法,并且只能通过反射调用C#。

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

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

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

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

你想要做的是:

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM