[英]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.