9

基本クラスDockedToolWindow:Formと、DockedToolWindowから派生した多くのクラスがあります。DockedToolWindowオブジェクトにイベントを保持して割り当てるコンテナクラスがありますが、子クラスからイベントを呼び出したいと思います。

このMSDNサイトから指示されていることを実装する方法について実際に質問があります。以下のこのセクションは私に問題を与えています:

    // The event. Note that by using the generic EventHandler<T> event type
    // we do not need to declare a separate delegate type.
    public event EventHandler<ShapeEventArgs> ShapeChanged;

    public abstract void Draw();

    //The event-invoking method that derived classes can override.
    protected virtual void OnShapeChanged(ShapeEventArgs e)
    {
        // Make a temporary copy of the event to avoid possibility of
        // a race condition if the last subscriber unsubscribes
        // immediately after the null check and before the event is raised.
        EventHandler<ShapeEventArgs> handler = ShapeChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

この例はコンパイルして機能しますが、「ShapeChanged」を「Move」(Formから派生して取得したイベント)に置き換えると、+=または-=がないと右側にMoveを設定できないというエラーが表示されます。ShapeEventArgs汎用タグも削除しました。

これが機能しない理由について何か刺激はありますか?クラス内で宣言されたイベントと継承されたイベントの違いは何ですか?

4

4 に答える 4

12

基本クラスのイベントを直接発生させることはできません。これがまさに、 の代わりにOnShapeChangedメソッドを作成しなければならなかった理由です。protectedprivate

代わりにbase.OnMove()を使用してください。

于 2009-04-23T09:36:56.343 に答える
4

C#言語仕様のセクション10.7(強調を追加)から:

イベントの宣言を含むクラスまたは構造体のプログラムテキスト内で、特定のイベントをフィールドのように使用できます。このように使用するには、イベントを抽象的または外部的であってはならず、event-accessor-declarationsを明示的に含めてはなりません。このようなイベントは、フィールドを許可する任意のコンテキストで使用できます。このフィールドには、イベントに追加されたイベントハンドラーのリストを参照するデリゲート(§15)が含まれています。イベントハンドラーが追加されていない場合、フィールドにはnullが含まれます。

したがって、Moveイベントをフィールドのように扱うことができない理由は、それが別のタイプ(この場合はスーパークラス)で定義されているためです。私は、デザイナーがイベントでの意図しないサルを防ぐためにこの選択をしたという@wompの推測に同意します。無関係な型(イベントを宣言する型から派生していない型)にこれを許可するのは明らかに悪いようですが、派生型であっても、望ましくない場合があります。おそらく、イベント宣言を実行できるようにするため、privateまたはprotectedフィールドスタイルの使用に関して構文を含める必要があったので、完全に許可しないことを選択したと思います。

于 2009-04-23T02:39:35.113 に答える
3

違いはスコープです。クラス内では、イベントデリゲートの処理方法を制御できますが、クラスは基本クラスの実行内容を制御できません。イベントとそのハンドラーを使って、舞台裏でクレイジーなことをしているのかもしれません。Moveイベントを単に「再割り当て」した場合は、イベントのマルチキャストデリゲートリストが消去されます。

これは非常に危険な方法であり、基本的にすべての子孫クラスにその親のイベントモデルを破棄する機能を与えるため、コンパイラの制限を課していると思います。

于 2009-04-23T02:15:19.197 に答える
1

イベント自体が定義されているクラスに投稿したコードのみが必要です。すべての派生クラスは、コピーなどを行わずに OnShapeChanged() または OnMove() を直接呼び出す必要があるため、クラスでそのコードをまったく記述しないでください (Move イベントはベースで定義されているため)。

派生クラスで何らかの処理を行う必要がある場合 (コレクション クラスをいじる必要があるのではないでしょうか?)、仮想 OnXXX 呼び出しをオーバーライドし、base.OnXXX() を呼び出す前に処理を行います。MSDN の記事では、Circle クラスは DockedToolWindow クラスに対応しています。派生クラスでも同じパターンを使用できるはずです。

于 2009-04-23T04:06:21.130 に答える