[英]C# UWP - how to pass additional parameter to an event handler at runtime
[英]How to pass around event as parameter in C#
我正在為多線程應用程序編寫單元測試,我需要等到觸發特定事件后才能知道異步操作已完成。 例如,當我調用repository.add(something)
,我等待事件AfterChange進行任何聲明。 所以我寫了一個實用函數來做到這一點:
public static void SyncAction(EventHandler event_, Action action_)
{
var signal = new object();
EventHandler callback = null;
callback = new EventHandler((s, e) =>
{
lock (signal)
{
Monitor.Pulse(signal);
}
event_ -= callback;
});
event_ += callback;
lock (signal)
{
action_();
Assert.IsTrue(Monitor.Wait(signal, 10000));
}
}
但是,編譯器阻止將事件傳遞到類之外。 有辦法實現嗎?
以下是使用反射的解決方案。
public static void SyncAction(object target_, string event_, Action action_)
{
SyncAction(
new List<Pair<object, string>>() { new Pair<object, string>(target_, event_) },
action_);
}
public static void SyncAction(IEnumerable<Pair<object, string>> events_, Action action_)
{
var events = events_
.Select(a => new Pair<object, EventInfo>(a.First, a.First.GetType().GetEvent(a.Second)))
.Where(a => a.Second != null);
var count = events.Count();
var signal = new object();
var callback = new EventHandler((s, e) =>
{
lock (signal)
{
--count;
Monitor.Pulse(signal);
}
});
events.ForEach(a => a.Second.AddEventHandler(a.First, callback));
lock (signal)
{
action_();
while (count > 0)
{
Assert.IsTrue(Monitor.Wait(signal, 10000));
}
}
events.ForEach(a => a.Second.RemoveEventHandler(a.First, callback));
}
問題在於事件實際上不是.NET中的一流值:((同上的屬性,方法等)
反應性擴展通過兩種方式處理此問題:
您可以提供事件和目標的名稱,它將使用反射...類似這樣:
var x = Observable.FromEvent<EventArgs>(button, "Click");
您可以提供一個用於訂閱的委托和一個用於取消訂閱的委托:
var x = Observable.FromEvent<EventArgs>( handler => button.Click += handler, handler => button.Click -= handler);
(確切的方法可能略有不同,但這是一般的想法。)
當然,如果您很高興自己使用反應性擴展,則可以使用這些方法並使測試使用IObservable<T>
:)
根據Jon Skeet的答案中使用的語法,這可能是一個自定義解決方案:
public static void AssertEventIsFired<T>(
Action<EventHandler<T>> attach,
Action<EventHandler<T>> detach,
Action fire) where T : EventArgs
{
AutoResetEvent fired = new AutoResetEvent(false);
EventHandler<T> callback = new EventHandler<T>(
(s, e) =>
{
detach(callback);
fired.Set();
});
attach(callback);
fire();
Assert.IsTrue(fired.WaitOne(10000));
}
用法:
AssertEventIsFired<EventArgs>(
h => obj.EventFired += h,
h => obj.EventFired -= h,
() => obj.DoSomethingToFireEvent());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.