2009-04-23 17 views
8

私は、基本クラスのDockedToolWindowを持っているで基本クラスのイベントレイズ:DockedToolWindowから派生フォーム、および多くのクラスを。私は保持し、DockedToolWindowオブジェクトにイベントを割り当てるコンテナクラスがありますが、子クラスからイベントを呼び出す必要があります。派生クラスC#

は、私が実際にこのMSDN siteは私が何を言っているものを実装する方法について質問があります。

// 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」を交換するとき、私はできないと言ってもエラー:以下のこのセクションでは、私に問題を与えています+ =または - =なしで右に移動してください。 ShapeEventArgs汎用タグも削除しました。

これはなぜ動作しないのですか?クラス内で宣言されたイベントと継承されたイベントの違いは何ですか?

答えて

12

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

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

+0

私はOnMove()がこれを解決することを見ていますが、OnMove()が必要なときにどのように明示的に呼び出すことができませんか?フレームワークがMove代理人を実際に呼び出す場所はわかりませんが、とにかく私は隠されているでしょう。 – Balk

+3

OnMoveはOnShapeChangedがコード内のShapeChangedイベントを発生させるのと同じ方法でMoveイベントを発生させます。イベントを発生させる保護されたメンバを追加して、派生したクラスでイベントを可視化するのが一般的なパターンです。その場合、通常は "On"プレフィックスが追加されます(OnMove、OnClickなど) – Groo

+0

フレームワークが実際にMoveイベントを発生させる場所を確認するには、Reflectorツール(http://www.red-gate.com/products/reflector /)を使用して、Form.OnMoveメソッドのソースコードを取得します。 – Groo

3

違いは範囲です。クラス内では、イベントデリゲートの処理方法を制御できますが、クラスでは基本クラスの動作を制御することはできません。イベントやそのハンドラーで何か狂った舞台裏をやっているかもしれない。単純にMoveイベントを "再割り当て"した場合、そのイベントのマルチキャストデリゲートリストが消去されます。

私は、彼らはその非常に危険な実践ので、この上のコンパイラの制限を入れて推測している、と本質的に任意の子孫クラスにその親のイベントモデルを破壊する能力を与えるだろう。 C#言語仕様、セクション10.7(強調追加)から

4

:イベントの宣言を含むクラスまたは構造体のプログラムテキスト内

、特定のイベントがフィールドように使用することができます。このように使用するには、イベントは抽象的または外部的であってはならず、イベント・アクセサ宣言を明示的に含めることはできません。このようなイベントは、フィールドを許可する任意のコンテキストで使用できます。フィールドには、イベントに追加されたイベントハンドラのリストを参照するデリゲート(15)が含まれています。イベントハンドラが追加されていない場合、フィールドにはnullが含まれます。

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

1

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

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

+0

OnMove()がこれを解決することがわかりましたが、OnMove()が必要なときにどのように明示的に呼び出すことができませんか?フレームワークがMove代理人を実際に呼び出す場所はわかりませんが、とにかく私は隠されているでしょう。 – Balk