2016-05-05 15 views
0

をインスタンス化された機能を所有しているオブジェクトの前にdelegate`機能in割り当て `私は正しいタイプの<code>Event</code>が渡された場合<code>Watcher</code>が<code>Event</code>に興味があると<code>Action</code>を起動するように設定することができるシステムに取り組んでいます

Actionには、起動時にEventに関する情報が必要です。

以下のコードでは、Watcherを設定するときに、イベント機能を渡した代理人をActionプロパティ(.NETのファクトではなく、フィールド/メンバー/その他)として使用します。

もちろんコードの問題は、// Step3にあるとき、私がそうすると、フィールドTheEventはヌルです。 WatcherEventが渡されると、それは判明します。私はそれがEventが割り当てられる前にEventから必要なプロパティを取得Actionだ作るためにWatcherを伝えることができますどのように

namespace ConsoleApplication1 
{ 
using System; 

internal class Program 
{ 
    static void Main(string[] args) 
    { 
     //Step1: choose the IEvent: NumericEvent 
     //Step2: create Watcher<NumbericEvent> 
     Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>(); 

     //Step3: Choose and add an action 
     aWatcher.TheAction = new AlphaAction(); 

     //Step3 bind the ActionProperties 
     aWatcher.TheAction.AnActionPropertyA = aWatcher.TheEvent.GetProperty1; 
     aWatcher.TheAction.AnActionPropertyB = aWatcher.TheEvent.GetProperty2; 


     //Step4 Bind the event 
     NumericEvent anEvent = new NumericEvent(); 
     aWatcher.Call(anEvent); 


    } 
} 

internal class AlphaAction 
{ 
    internal delegate string ActionPropertyA(); 
    internal delegate int ActionPropertyB(); 

    internal ActionPropertyA AnActionPropertyA; 
    internal ActionPropertyB AnActionPropertyB; 
    internal string ActionPropertyC; 

    public void Run() 
    { 
     Console.Write(AnActionPropertyA.Invoke()); 
     Console.Write(AnActionPropertyB.Invoke()); 
    } 
} 


internal interface IEvent 
{ 
} 

internal class NumericEvent:IEvent 
{ 
    internal string EventProperty1 = "Property1"; 
    internal int EventProperty2 = 2; 

    internal string GetProperty1() 
    { 
     return EventProperty1; 
    } 
    internal int GetProperty2() 
    { 
     return EventProperty2; 
    } 

} 

internal class Watcher<T> where T:IEvent 
{ 
    internal NumericEvent TheEvent; 
    internal AlphaAction TheAction; 

    internal void Call(IEvent anEvent) 
    { 
     TheEvent = (NumericEvent)anEvent; 
     TheAction.Run(); 
    } 
} 
} 

おそらく完全に異なるアプローチをとる必要がありますが、私はこれが問題とその結果を望むことを望みます。


UPDATE

私はDelegate.CreateDelegate(https://msdn.microsoft.com/en-us/library/s3860fy3.aspx)を使用して、いくつかのprogerssを作ったが、nullの場合は割り当てられたとき、それは静的として扱いだとして、それはまだかなり右ではありません。

名前空間をConsoleApplication1 { using System; using System.Reflection;私はよくして、あなたがGalasoft's MVVM Light Toolkitを利用することができますあなたの必要性を理解していれば

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

     //Step1: choose the IEvent: NumericEvent 
     //Step2: create Watcher<NumbericEvent> 
     Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>(); 

     //Step3: Choose and add an action 
     aWatcher.TheAction = new AlphaAction(); 

     //Step3 bind the ActionProperties 

     MethodInfo method1 = typeof(NumericEvent).GetMethod("GetProperty1"); 
     aWatcher.TheAction.AnActionPropertyA = (AlphaAction.ActionPropertyA)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyA), aWatcher.TheEvent, method1); 

     MethodInfo method2 = typeof(NumericEvent).GetMethod("GetProperty2"); 
     aWatcher.TheAction.AnActionPropertyB = (AlphaAction.ActionPropertyB)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyB), aWatcher.TheEvent, method2); 

     //Step4 an event is created and passed to the Watcher 
     NumericEvent anEvent = new NumericEvent("bla",3); 
     if (aWatcher.GType() == anEvent.GetType()) 
      aWatcher.Call(anEvent); 

    } 
} 

internal abstract class BaseAction 
{ 
    public abstract void Run(); 
} 

internal class AlphaAction: BaseAction 
{ 
    internal delegate string ActionPropertyA(); 
    internal delegate int ActionPropertyB(); 

    internal ActionPropertyA AnActionPropertyA; 
    internal ActionPropertyB AnActionPropertyB; 
    internal string ActionPropertyC; 

    public override void Run() 
    { 
     Console.Write(AnActionPropertyA.Invoke()); 
     Console.Write(AnActionPropertyB.Invoke()); 
    } 
} 


internal interface IEvent 
{ 
} 

internal class NumericEvent : IEvent 
{ 
    private readonly string _eventProperty1; 
    private readonly int _eventProperty2; 

    public NumericEvent(string p1, int p2) 
    { 
     _eventProperty1 = p1; 
     _eventProperty2 = p2; 
    } 

    public string GetProperty1() 
    { 
     return _eventProperty1; 
    } 
    public int GetProperty2() 
    { 
     return _eventProperty2; 
    } 

} 

internal class Watcher<T> where T:IEvent 
{ 
    internal T TheEvent; 
    internal AlphaAction TheAction; 

    internal Type GType() 
    { 
     return typeof(T); 
    } 

    internal void Call(IEvent anEvent) 
    { 
     TheEvent = (T)anEvent; 
     TheAction.Run(); 
    } 
} 

}

+0

私の主なポイントは、イベントに依存するアクションを持っていないが、ウォッチャーは正しいイベントプロパティをアクションに結び付けることです。ウォッチャー(したがって同じイベント)に対して複数のアクション(アクションのサブクラス実装が異なる)が存在し、同じアクションが異なるウォッチャーによって使用される可能性があります。つまり、異なるイベントで呼び出すことができます。したがって、アクションはイベントから完全に分離する必要があります。このアクションは、値を取得する方法を知る必要があるだけです。 – EasierSaidThanDone

+0

'Delegate.CreateDelegate'を使用して解決策に近づいていますが、まだそれほど正しくありません....' MethodInfo method1 = typeof(NumericEvent).GetMethod( "GetProperty1" ); \t \t \t aWatcher.TheAction.AnActionPropertyA =(AlphaAction.ActionPropertyA)Delegate.CreateDelegate(typeof演算(AlphaAction.ActionPropertyA)、aWatcher.TheEvent、法1); ' – EasierSaidThanDone

+0

だから' aWatcher.TheEvent'が時間 'createDelegate'にヌルでありますデリゲート 'AnActionPropertyA'が呼び出されたときには呼び出されますが、呼び出されません。 - >割り当てられた 'aWatcher 'を使用する方法はありますか?TheEvent'? – EasierSaidThanDone

答えて

1

あなたのコードの問題は(および更新されたコードaWatcher.TheAction.AnActionPropertyA = (AlphaAction.ActionPropertyA)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyA), aWatcher.TheEvent, method1);中)aWatcher.TheAction.AnActionPropertyA = aWatcher.TheEvent.GetProperty1;ラインでaWatcher.TheEventです。

aWatcher.TheEventは、デリゲートは、デリゲートは常にnullを使用して作成された時点でnullですので。後でイベントをTheEvent = (NumericEvent)anEvent;という行に割り当てても構いません。

これを機能させるには、将来クラスがあることを代理人に知らせる必要があります。ここで私はそれをやる方法はありますが、あなたがそれをどのように動作させるかというあなたの論理に何かを打ち破るものと思われます。

void Main() 
{ 
    Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>(); 
    aWatcher.TheAction = new AlphaAction<NumericEvent>(); 
    aWatcher.TheAction.AnActionPropertyA = ne => ne.GetProperty1(); 
    aWatcher.TheAction.AnActionPropertyB = ne => ne.GetProperty2(); 
    NumericEvent anEvent = new NumericEvent("bla", 3); 
    if (aWatcher.GType() == anEvent.GetType()) 
     aWatcher.Call(anEvent); 
} 

internal abstract class BaseAction<T> where T : IEvent 
{ 
    public abstract void Run(T theEvent); 
} 

internal class AlphaAction<T> : BaseAction<T> where T : IEvent 
{ 
    internal delegate string ActionPropertyA(T theEvent); 
    internal delegate int ActionPropertyB(T theEvent); 

    internal ActionPropertyA AnActionPropertyA; 
    internal ActionPropertyB AnActionPropertyB; 

    public override void Run(T theEvent) 
    { 
     Console.Write(AnActionPropertyA(theEvent)); 
     Console.Write(AnActionPropertyB(theEvent)); 
    } 
} 

internal interface IEvent 
{ 
} 

internal class NumericEvent : IEvent 
{ 
    private readonly string _eventProperty1; 
    private readonly int _eventProperty2; 

    public NumericEvent(string p1, int p2) 
    { 
     _eventProperty1 = p1; 
     _eventProperty2 = p2; 
    } 

    public string GetProperty1() 
    { 
     return _eventProperty1; 
    } 
    public int GetProperty2() 
    { 
     return _eventProperty2; 
    } 
} 

internal class Watcher<T> where T : IEvent 
{ 
    internal AlphaAction<T> TheAction; 

    internal Type GType() 
    { 
     return typeof(T); 
    } 

    internal void Call(T theEvent) 
    { 
     TheAction.Run(theEvent); 
    } 
} 
+0

はい!それはまさに問題です。私が1000行で書いたものよりもずっと多くの点。私はアクションをジェネリックにすることで逃げることができると思うので、あなたの答えはちょうどうまくいくかもしれません。ありがとう。 – EasierSaidThanDone

+0

これは@Enigmativityでもうまくいきましたが、もう別の問題に直面しています。 'aWatcher.TheAction.AnActionPropertyA = ne => ne.GetProperty1();'は、 'Action'がすでにインスタンス化されているときに一度に設定することはできません。代わりに 'AlphaAction の文字列表現をこの' dynamic actionInstance = Activator.CreateInstance(ActionType); '(これは異なる' XyAction <123Event> ')のように' Action'の実際のインスタンスに変換します。 neの型が不明で、 'GetProperty1()'が利用できないので、 'aWatcher.TheAction.AnActionPropertyA = ne => ne.GetProperty1();'を実行できません!アイデア? – EasierSaidThanDone

+0

@EasierSaidThanDone - このコードで何をしようとしているのですか? 1つのレベルの抽象化? – Enigmativity

1

点は以下の通りである:

  • 例えば、メッセージ・タイプを定義しますSomeMessage
  • 通知を受けたいこのタイプのメッセージに登録します。
  • 「イベント」は、SomeMessageのインスタンスを送信することによって発生させることができます。
  • このメッセージに登録されているすべてのアクションが実行されます。

のは例を見てみましょう:

// First you create the message with the needed properties. 
public SomeMessage 
{ 
    public string Content { get; set; } 
} 

// Then at some places you register for listening to this type of message 
Messenger.Default.Register<SomeMessage>(
    this, 
    message => YourMethodThatProcessesTheMessage(message) 
); 

// Your method knows the exact type of the message 
// So you can access all the properties of the message 
private void YourMethodThatProcessesTheMessage(SomeMessage message) 
{ 
    Console.WriteLine(message.Content); 
} 

// At another place you can simply send a message to all the listeners 
var message = new SomeMessage() { Content = "something" }; 
Messenger.Default.Send<SomeMessage>(message); 
+0

あなたの答えをありがとう。あなたの意見が正しいとすれば、私は回避しようとしているActionとEvenの間に依存関係があります。 – EasierSaidThanDone

+0

'SomeMessage'は' event'自体ではなく 'EventArgs'の一種です。このメッセージに複数の場所で登録し、そこにさまざまなアクションを定義することができます。もちろん 'SomeMessage'は' Action 'デリゲートプロパティを持つことができ、' SomeMessage'をインスタンス化するときにデリゲートを設定することができます。 'var message = new SomeMessage(){ActionA = YourMethod、ActionB = YourOtherMethod};'受信者はそれらを実行します。 'message.ActionA();' – Gabor

1

私が正しくあなたを理解していれば、あなたが次のことをやりたい。それはクラスにアクションを渡されるときに、特定のイベントを検索し、Watcherクラスを持っています解雇され、イベントは議論として渡されるべきである。

あなたは穴の事を必要とする理由私は完全には理解していないと、なぜあなたは、物事にあなたが行った方法を設定しますが、ここで役立つかもしれない単純な実装です:

internal interface IEvent { } 

internal class Watcher<T> where T : IEvent 
{ 
    internal Action<T> Action; 

    public void On(IEvent evnt) 
    { 
     if (evnt is T) Action?.Invoke((T) evnt); 
    } 
} 

あなたが実装することにより、新しいイベントを作成することができますIEventを入力し、指定されたタイプのアクションがウォッチャーによって登録されたときに起動されるアクションを登録することができます。Actionフィールドを設定します。例えば

var watcher = new Watcher<NumberEvent>(); 
watcher.Action += e => Console.WriteLine($"Got a number: {e.Number}"); 

watcher.On(new StringEvent { Text = "hello"}); 
watcher.On(new NumberEvent { Number = 1337}); 

私が正しくあなたの問題を理解していない(と私はしなかった大きなチャンスがある)場合、これらは

internal class NumberEvent : IEvent 
{ 
    internal int Number; 
} 

internal class StringEvent : IEvent 
{ 
    internal string Text; 
} 

を定義しているプログラムが行うことになっているかを説明してください。ここで

は、実装上のいくつかの考え/ご質問は以下のとおりです。

  • あなたは、一般的なウォッチャクラス(Watcher<T>)を作成しているが、Tはウォッチャの内部で使用されていません。 NumericEventTに置き換えて、IEventのタイプがT(またはご使用の場合はNumericEvent)であるかどうかを確認してください。あなたのコーディングにより、IEventはかなり古くなりました。
  • C#のプロパティはstring EventProperty { get; }です。 GetProperty1()メソッドを作成する必要はありません(フィールドも内部的なので、なぜメソッドを使用するのですか?)
  • イベントをアクションに供給するだけで、アクションにイベントをホットラインしないでください。
+0

あなたの答えをありがとう。私の主なポイントは、イベントに依存するアクションを持っていないが、ウォッチャーがアクションに適切なイベントプロパティを結ばせることです。ウォッチャー(したがって同じイベント)に対して複数のアクション(アクションのサブクラス実装が異なる)が存在し、同じアクションが異なるウォッチャーによって使用される可能性があります。つまり、異なるイベントで呼び出すことができます。したがって、アクションはイベントから完全に分離する必要があります。アクションは、値を取得する方法を知る必要があります。あなたの最終的な点を再確認してください:プロダクションコードでは、それは確かにそういうことでしょう、これは単なる例です:) – EasierSaidThanDone

関連する問題

 関連する問題