Я пишу модульные тесты для многопоточного приложения, где мне нужно подождать, пока не будет запущено определенное событие, чтобы я знал, что выполняется асинхронная операция. Например, когда я вызываю repository.add(something)
, я жду события AfterChange перед выполнением любого утверждения. Поэтому я написал функцию полезности для этого:Как передать событие как параметр в C#
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));
}
Am с использованием 2-й подход, и будет пытаться на отражение. Rx еще не утвердил в моей компании, что я не могу ждать. Но определенно будет намного легче написать тестовые примеры, используя Rx. –