まず、良い質問です。「ベストプラクティス」を盲目的に受け入れるのではなく、ユーティリティに焦点を当てていることを称賛します。そのために+1。
以前にそのガイドを読んだことがあります。それについて何か覚えておく必要があります-これは単なるガイドであり、主にプログラミングの方法は知っているが、C#のやり方をよく知らないC#の初心者向けです。ルールのページというよりも、すでに通常行われていることを説明するページです。そして、彼らはすでにこの方法でどこでも行われているので、一貫性を保つことは良い考えかもしれません。
あなたの質問に答えて要点を説明します。
まず第一に、インターフェイスが何であるかを既に知っていると思います。デリゲートに関しては、メソッドへの型付きポインタと、this
そのメソッドの引数を表すオブジェクトへのオプションのポインタを含む構造であると言えば十分です。静的メソッドの場合、後者のポインターはnullです。
マルチキャストデリゲートもあります。これは、デリゲートに似ていますが、これらの構造のいくつかが割り当てられている場合があります(マルチキャストデリゲートでInvokeを1回呼び出すと、割り当てられた呼び出しリスト内のすべてのメソッドが呼び出されます)。
イベントデザインパターンとはどういう意味ですか?
それらは、C#でイベントを使用することを意味します(これには、この非常に便利なパターンを巧みに実装するための特別なキーワードがあります)。C#のイベントは、マルチキャストデリゲートによって促進されます。
この例のように、イベントを定義する場合:
class MyClass {
// Note: EventHandler is just a multicast delegate,
// that returns void and accepts (object sender, EventArgs e)!
public event EventHandler MyEvent;
public void DoSomethingThatTriggersMyEvent() {
// ... some code
var handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
// ... some other code
}
}
コンパイラは実際にこれを次のコードに変換します。
class MyClass {
private EventHandler MyEvent = null;
public void add_MyEvent(EventHandler value) {
MyEvent += value;
}
public void remove_MyEvent(EventHandler value) {
MyEvent -= value;
}
public void DoSomethingThatTriggersMyEvent() {
// ... some code
var handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
// ... some other code
}
}
次に、イベントをサブスクライブします
MyClass instance = new MyClass();
instance.MyEvent += SomeMethodInMyClass;
コンパイルする
MyClass instance = new MyClass();
instance.add_MyEvent(new EventHandler(SomeMethodInMyClass));
C#(または.NET全般)のイベントです。
デリゲートを使用した場合、どのように構成が簡単になりますか?
これは簡単に実証できます:
渡される一連のアクションに依存するクラスがあるとします。これらのアクションをインターフェースにカプセル化できます。
interface RequiredMethods {
void DoX();
int DoY();
};
そして、アクションをクラスに渡したい人は、最初にそのインターフェースを実装する必要があります。または、次のクラスに依存することにより、彼らの生活を楽にすることができます。
sealed class RequiredMethods {
public Action DoX;
public Func<int> DoY();
}
このように、呼び出し側はRequiredMethodsのインスタンスを作成し、実行時にメソッドをデリゲートにバインドするだけです。これは通常簡単です。
この方法は、適切な状況下で非常に有益です。それについて考えてください-本当にあなたが気にかけているのは、あなたに渡された実装を持っているだけなのに、なぜインターフェイスに依存するのですか?
関連するメソッドのグループがある場合にインターフェースを使用する利点
インターフェイスは通常、明示的なコンパイル時の実装を必要とするため、インターフェイスを使用することは有益です。これは、新しいクラスを作成することを意味します。
また、単一のパッケージに関連するメソッドのグループがある場合、そのパッケージをコードの他の部分で再利用できると便利です。したがって、一連のデリゲートを構築するのではなく、クラスを単純にインスタンス化できれば、簡単です。
クラスが1つの実装のみを必要とする場合にインターフェースを使用する利点
前述のように、インターフェイスはコンパイル時に実装されます。つまり、デリゲート(それ自体が間接的なレベルです)を呼び出すよりも効率的です。
「1つの実装」とは、明確に定義された単一の場所に存在する実装を意味する場合があります。
それ以外の場合、実装はプログラムのどこからでも発生する可能性があり、たまたまメソッドシグネチャに準拠しています。メソッドは、特定のインターフェイスを明示的に実装するクラスに属するのではなく、予想される署名に準拠するだけでよいため、柔軟性が高まります。しかし、その柔軟性は犠牲になる可能性があり、実際にはリスコフの置換原則を破ります。なぜなら、ほとんどの場合、事故の可能性を最小限に抑えるため、明示性が必要だからです。静的入力と同じです。
この用語は、ここでマルチキャストデリゲートを指す場合もあります。インターフェイスによって宣言されたメソッドは、実装クラスで1回しか実装できません。ただし、デリゲートは複数のメソッドを蓄積することができ、それらは順次呼び出されます。
全体として、ガイドは十分な情報を提供しておらず、単にルールブックではなくガイドとして機能しているように見えます。いくつかのアドバイスは実際には少し矛盾するように聞こえるかもしれません。何を適用するのが適切かを決めるのはあなた次第です。このガイドは、一般的な道筋のみを示しているようです。
あなたの質問があなたの満足に答えられることを望みます。そして再び、質問への称賛。