8

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
}
4

7 に答える 7

11

インターフェイスの概念は、実装ではなく、コントラクトを表すことです。

ILが実際にインターフェイスに実装された静的メソッドを許可しているかどうかをすぐに思い出せません-私はそれが許可しているという卑劣な疑いを持っています-しかしそれは概念をいくらか混乱させます。

私はあなたのポイントを見ることができます-インターフェースに接続されているどのヘルパーメソッドが利用可能であるかを知ることは時々役に立ちます(そして拡張メソッドはそこで特に関連しています)が、メンタルを保つために、とにかくそれらを別のクラスに入れたいと思いますきれいなモデル。

于 2009-06-30T08:44:10.283 に答える
6

私はこれに数回遭遇し、いくつかの調査を行いました。悲しいことに、IL は実際にこれをサポートしています。私はこれにとてもイライラしたので、それについてブログ記事を書きました。ここで見つけることができます。

于 2009-06-30T09:10:51.073 に答える
2

あなたの目的のために、プラグインインターフェースをプラグインローダーの実装から切り離す方がはるかに良いでしょう:これはあなたのデザインをはるかに結合しにくくし、よりまとまりのあるものにします(したがって複雑さを減らします)。

「インターフェイスの静的メソッド」については、こちらをご覧ください

そして補足として:あなたは本当に別のプラグインアーキテクチャを発明したくありません:MEFを見てください。

于 2009-06-30T08:42:56.840 に答える
2

インターフェイスに実装された静的メソッドに関する私のブログエントリをチェックしてください(恥知らずな自己参照のために申し訳ありません)

[壊れたリンク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#はインターフェイスに実装された静的メソッドをサポートしていないため、C#コンパイラ(MS C#)はコードをコンパイルせず、C#からはリフレクションを介してのみ呼び出すことができます。

私はSharpDevelopなどの他のIDEでテストしていません...したがって、この状況にどのように対処するかはまだわかりません。

于 2009-06-30T09:48:12.870 に答える
1

インターフェースはまさにそれ、インターフェースです。動作を説明するために使用されることを意図したものではありません。クラスがインターフェースを実装するとき、クラスは「メソッド/イベントなどにこれらの署名を提供することを約束します」とだけ言います。

必要なのは、静的メソッドのないインターフェイスと、インターフェイスと静的メソッドを実装する抽象基本クラスです。次に、他のクラスが基本クラスから継承し、インターフェイスのメソッド実装を変更できます。しかし、これでも疑わしい設計です。

于 2009-06-30T08:48:42.100 に答える
0

静的メソッドは、それらが宣言されているタイプに関連付けられており、オーバーライドには関係ありません。静的メソッドをインターフェースにアタッチできた場合は、インターフェース自体を介してそれを参照する必要があります。ITaskPlugin.GetPlugins(...)

あなたがしたいことは次のいずれかです:

1)インターフェイスは実装コードを保持するように設計されていないため、メソッドを抽象基本クラスに配置します。

2)インターフェイスに適用される拡張メソッドを作成すると、基本クラスを使用せずにインターフェイスにアクセスできるようになります。

于 2009-06-30T08:44:40.877 に答える
0

インターフェイスの目的は、オブジェクトにアクセスできるオブジェクトのインターフェイスを宣言することです。これが唯一の目的であるという事実のために、コードをインターフェースに配置することを許可することは意味がありません。それでもインターフェースにコードを追加したい場合は、拡張メソッドを使用できます。

于 2009-06-30T08:47:29.730 に答える