2011-01-13 13 views
2

私は基本的なタイプの間で適応ジェネリッククラスのAdapterパターンを持っている:イベント+ Adapterパターン

class A<T> { event EventHandler e; } 
class Aadapter<T1, T2> : A<T1> { A<T2> a; Aadapter(A<T2> _a) { a = _a; } } 

問題は、Aは、イベントが含まれていることです。私は効果的に、アダプタに割り当てられたすべてのイベントハンドラが〜に落ちるようにしたい。

アダプタのイベントハンドラにイベントハンドラを割り当てることはできますが、これは不可能ですか?

ここでのアイデアは、Aはほぼ本当にAですが、それらを適応させる方法が必要です。イベントの仕組みのため、2つのイベントハンドラを手動で追加し、呼び出されたときに他のイベントに「リレー」する以外は、効率的に行う方法がありません。これはかなりかかわらずではないと私は、我々は、A2のイベントを割り当てることができますイベントへのポインタを持っている意味で

class A<T> { event EventHandler e; } 
class Aadapter<T1, T2> : A<T1> { event *e; A<T2> a; Aadapter(A<T2> _a) { a = _a; e = a.e; } } 

のようなものを持っていることができれば、それは非常に良く思われます。

私は単純な方法があるとは思っていませんが、多分誰かがそれを働かせるように考えているかもしれません。

答えて

0

はなぜ加入するときれいではありませんイベントを転送している(ちなみに、私は、これは仮想イベントで可能であるが、私は全く可能であればこれを避けるしたいの実現しますか)?私はそれがエレガントな見つける。

これを行うことは、残りのアダプタの実装方法と一貫しています。

でもにポインタを使用しても、すべての場合にそうしたくないため、矛盾します。

たとえば、INotifyPropertyChangedを実装するクラスを、「TitleChanged」や「MaxLengthChanged」などの2つのプロパティを公開するインターフェイスに適用する場合は、ポインタを使用しません。アダプターはこれらの2つのイベントを公開し、消費者は購読します。アダプターはPropertyChangedイベントを購読し、 "Title"が変更されたことを通知された場合にのみ "TitleChanged"を引き上げ、 "MaxLength"が変更されたことを通知された場合にのみ "MaxLengthChanged"他のすべての通知は無視されます。

このアプローチは、わかりやすく、パターンに一貫性があり、真実であると私は好む。

+0

この場合、このアダプターは汎用クラスをそれ自身に適応させています。クラスのジェネリック型パラメータは、それほど使用されていないという意味でややゆるやかにバインドされています。これは、クラスがジェネリックパラメータとはほとんど無関係であり、アダプタはほとんど必要ないことを意味します。 このような状況では、イベントをアダプタからラップされたオブジェクトに結びつけるのではなく、両方をサブスクライブする方が自然です。 明らかに "ポインタメソッド"はうまくいかず、誰かがより良いやり方を思い出さなければ、私は仕事をする2人から選ぶことに悩まされます。 – Stretto

1

私はこれがあると思いますが何であるかの後:

class A<T> 
    { 
     public virtual event EventHandler e; 
    } 

    class Aadapter<T1, T2> : A<T1> 
    { 
     A<T2> a; 
     Aadapter(A<T2> _a) { a = _a; } 
     public override event EventHandler e 
     { 
      add { a.e += value; } 
      remove { a.e -= value; } 
     } 
    } 

やチェーンそれの問題を解決するために、「標準」方法を示す

class A<T> 
{ 
    public event EventHandler e; 

    protected void ChainEvent(object sender, EventArgs eventArgs) 
    { 
     e(sender, eventArgs); 
    } 
} 
class Aadapter<T1, T2> : A<T1> 
{ 
    A<T2> a; 
    Aadapter(A<T2> _a) 
    { 
     a = _a; 
     a.e += ChainEvent; 
    } 
} 
+0

私が言ったように、これは一つのアプローチですが、私はむしろそれを取っていません。 (余分なオーバーヘッドに加えて、C#で仮想イベントに関する既知の問題もあります) – Stretto

+0

@Stretto仮想イベントに関連するオーバーヘッドは何ですか? – Jay

+0

既知の問題は何ですか? – Neil

0

例。第1のものは仮想イベント/方法を使用し、第2のものは「倍増終了」転送方式を使用する。どちらもプロとコンプを持っていますが、イベントの数が増えないほど簡単な方法があればいいと思います。私たちがやりたいことは、この2つのイベントを間接的にではなく直接的に組み合わせることです。これは、このコードが行うことです。コードは今すぐイベントを容易に割り当てることができ、効果的に表すクラスのイベントをラップする新しい方法を含む:

//#define __virtual 
#define __direct 

using System; 
using System.Collections.Generic; 
using System.Text; 



namespace VirtualEvents 
{ 



    #if __virtual 
    #region 
    public class A<T> 
    { 
     public virtual event EventHandler e; 

     public virtual void Fire() { e(this, null); } 
    } 

    public class Aadapter<T1, T2> : A<T1> 
    { 
     A<T2> a; 


     public override event EventHandler e 
     { 
      add { a.e += new EventHandler(value); } 
      remove { a.e -= new EventHandler(value); } 
     } 

     public override void Fire() 
     { 
      a.Fire(); 
     } 

     public Aadapter(A<T2> _a) 
     { 
      a = _a; 
     } 
    } 
    #endregion 
    #elif __direct 
    #region 

    public delegate EventHandler EventHandlerPtr(); 
     public class eventPtr 
     { 
      public EventHandler _event; 
     } 
    public class A<T> 
    { 


     //internal EventHandler _event; 
     public eventPtr _event = new eventPtr(); 

     public event EventHandler e 
     { 
      add { _event._event += value; } 
      remove { _event._event -= value; } 
     } 

     public void Fire() { _event._event(this, null); } 


    } 

    public class Aadapter<T1, T2> : A<T1> 
    { 
     A<T2> a; 

     public Aadapter(A<T2> _a) 
     { 
      a = _a; 
      this._event = a._event; 
     } 
    } 

    #endregion 
    #else 
    #region 
    public class A<T> 
    { 
     public event EventHandler e; 

     public void Fire() { e(this, null); } 
    } 

    public class Aadapter<T1, T2> : A<T1> 
    { 
     A<T2> a; 

     public Aadapter(A<T2> _a) 
     { 
      a = _a; 

      a.e += new EventHandler(a_e); 
      e += new EventHandler(Aadapter_e); 
     } 

     void Aadapter_e(object sender, EventArgs e) 
     { 
      a.e -= new EventHandler(a_e); 
      a.Fire(); 
      a.e += new EventHandler(a_e); 
     } 

     void a_e(object sender, EventArgs e) 
     {  
      this.e -= new EventHandler(Aadapter_e); 
      Fire(); 
      this.e += new EventHandler(Aadapter_e); 
     } 
    } 
    #endregion 
    #endif 


    class Program 
    { 
     static void Main(string[] args) 
     { 

      var a = new A<double>(); 
      var q = new Aadapter<int, double>(a); 

      a.e += new EventHandler(a_e); 
      q.e += new EventHandler(q_e); 


      a.Fire(); 
      q.Fire(); 
      ((A<int>)q).Fire(); 

      Console.ReadKey(); 
     } 

     static void a_e(object sender, EventArgs e) 
     { 
      Console.WriteLine("From a"); 
     } 

     static void q_e(object sender, EventArgs e) 
     { 
      Console.WriteLine("From q"); 
     } 

    } 
} 

(編集(それらはC#で可能であった場合、ポインタは、このような方法であろう) "ポインタ"の場合。誰かがこれをさらに改善することができたらうれしいです。)

+0

ところで、動作する1つの方法は、独自のイベント構成をロールバックすることです。例えば、リスト/ハッシュテーブルおよびコールバックを使用する。この場合、ラップされたオブジェクトのコールバックリストをアダプタクラス内の参照に簡単に割り当てることができます。イベントセマンティクスを使用してこれを行うことができると思います...私はそれがまともな解決策かもしれないので、それを試さなければなりません。 – Stretto