タイプに基づいたC#オブザーバー?
-
08-07-2019 - |
質問
タイプに基づいてオブザーバーのセットを作成するとします。つまり、イベントが通知されると、引数の1つのタイプが通知され、そのタイプを操作できるかどうかに基づいてアクションを実行するかどうかを決定します。
これを行う簡単な方法はありますか?これはジェネリックで行うのはかなり簡単だと思いましたが、それは想像よりも難しいことが判明したようです。そして、もしそれを避けることができれば、オブジェクトへの参照の束をキャストする必要はありません。
私が立ち往生しているのは、これを行うことです:
public delegate void NotifyDelegate<T>(IEnumerator<T> loadable, NotifyArgs na);
interface IObserver
{
void Notify<T>(IEnumerator<T> loadable, NotifyArgs na);
}
class Subject
{
NotifyDelegate notifier; //won't compile: needs type args
void Register(IObserver o)
{
notifier += o.Notify;
}
}
もちろん、Subjectをジェネリックにすることもできますが、タイプごとに個別のSubjectが必要です。誰かアドバイスはありますか?どこかに欠けている機能がありますか、それとも複雑すぎますか?
UPDATE :NotifyとNotifyDelegateが取る引数を単純化しすぎました。これの代わりに:
public delegate void NotifyDelegate<T>(NotifyArgs na);
私は実際に次のようなことをしたいです:
public delegate void NotifyDelegate<T>(IEnumerator<T> loadable, NotifyArgs na);
基本的にやり取りしようとしているのは、データベースからのデータです。前のコードサンプルで誰もが混乱した場合は申し訳ありません。
解決
まず、持っているコードを次のように変更します。
interface IObserver
{
}
class Subject
{
public Subject ()
{
m_observers = new List<IObserver> ();
}
public void Register (IObserver o)
{
m_observers.Add (o);
}
List<IObserver>
m_observers;
}
次に、リフレクションを使用して、パラメーターの種類に基づいて適切な関数を見つけます:
public void NotifyObservers (object param)
{
foreach (IObserver observer in m_observers)
{
foreach (MethodInfo method in observer.GetType ().GetMethods (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance))
{
if (method.Name == "Notify")
{
ParameterInfo []
parameters = method.GetParameters ();
if (parameters.Length == 1 && parameters [0].ParameterType == param.GetType ())
{
method.Invoke (observer, new object [] { param });
break;
}
}
}
}
}
次のように使用します:
class Observer : IObserver
{
public Observer (Subject s)
{
s.Register (this);
}
void Notify (float value)
{
System.Diagnostics.Trace.WriteLine ("float value = " + value);
}
void Notify (int value)
{
System.Diagnostics.Trace.WriteLine ("int value = " + value);
}
}
static void Main (string [] args)
{
Subject
s = new Subject ();
Observer
o = new Observer (s);
float
v1 = 3.14f;
int
v2 = 42;
System.Diagnostics.Trace.WriteLine ("sending float");
s.NotifyObservers (v1);
System.Diagnostics.Trace.WriteLine ("sending int");
s.NotifyObservers (v2);
}
他のヒント
interface IObserver
{
void Notify(NotifyArgs na);
bool SupportsType(Type t);
}
class Subject
{
List<IObserver> observers;
void Register(IObserver o)
{ observers.Add(o);
}
void OnNotify(Type t, NotifyArgs args)
{
foreach (IObserver o in observers)
{
if (o.SupportsType(t)) o.Notify(args));
}
}
}
所属していません StackOverflow