おはよう! 私の目的は、オブジェクトの購読や購読をイベントから(やりとりする)ことができるクラスを実装することです。ここに私のクラスのコードです。リフレクションによるイベントハンドラの追加と削除c#
public static class EventSubscriber
{
public static void AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.RemoveEventHandler(item, handler);
}
private static ParameterExpression[] GetParameters(EventInfo eventInfo)
{
return eventInfo.EventHandlerType
.GetMethod("Invoke")
.GetParameters()
.Select(parameter => Expression.Parameter(parameter.ParameterType))
.ToArray();
}
private static Delegate GetHandler(EventInfo eventInfo,
Action action, ParameterExpression[] parameters)
{
return Expression.Lambda(
eventInfo.EventHandlerType,
Expression.Call(Expression.Constant(action),
"Invoke", Type.EmptyTypes), parameters)
.Compile();
}
}
ご覧のとおり、オブジェクトを実際に購読したり購読を解除したりする2つのパブリックメソッドがあります。そして、ここで私は、サンプルの
class Program
{
static void Main()
{
Test test = new Test();
test.SubscribeTimer();
while (true)
{
if(test.a == 10)
{
break;
}
}
test.UnsubscribeTimer();
while (true)
{
}
}
}
class Test
{
System.Timers.Timer timer;
public int a = 0;
public Test()
{
timer = new System.Timers.Timer(1000);
timer.Start();
}
public void SubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerNotElapsed);
}
public void UnsubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerNotElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerElapsed);
}
public void TimerElapsed()
{
Console.WriteLine("timer elapsed");
a++;
}
public void TimerNotElapsed()
{
Console.WriteLine("timer not elapsed");
a++;
}
}
予想される動作は、初めに、我々はメッセージ10番目秒後に我々は唯一の「しないタイマを参照する必要があり、毎秒「のタイマーが経過する」を参照してくださいということですそれをテストする方法サンプルです私たちはやっていますが、まだ "タイマー経過"を見ています。つまり、AddEventHandlerメソッドは機能しますが、RemoveEventHandlerメソッドは機能しません。
あなたが私を助けるならば、私はとても幸せです。前もって感謝します。
、デリゲートは完全に一致する必要があります。同じメソッドとターゲットプロパティ。ターゲットは同じではありません。 btwを見るのが非常に難しく、ClosureオブジェクトはExpression.Lambda()によって非常に難読化されています。かわいいトリックですが、私は真剣にあなたがそれを動作させることができると疑う。また、スレッドの要件に違反していることにも注意してください。変数の更新を確認することはできません。 –
返信いただきありがとうございます!だから、イベントハンドラのシグネチャをデリゲートタイプのイベントのシグネチャと同じにするなら、私がサンプルに書いたように私は退会することができますか? – Crispried