private void AttachEventHandler(EventInfo eventInfo, Func <DateTime> utcNow) { if (!recorderMap.TryGetValue(eventInfo.Name, out _)) { var recorder = new EventRecorder(subject.Target, eventInfo.Name, utcNow); if (recorderMap.TryAdd(eventInfo.Name, recorder)) { recorder.Attach(subject, eventInfo); } } }
/// <summary> /// Obtains the <see cref="EventRecorder"/> for a particular event of the <paramref name="eventSource"/>. /// </summary> /// <param name="eventSource">The object for which to get an event recorder.</param> /// <param name="eventName">The name of the event.</param> /// <returns></returns> public static EventRecorder GetRecorderForEvent <T>(this T eventSource, string eventName) { EventRecorder eventRecorder = Map[eventSource].FirstOrDefault(r => r.EventName == eventName); if (eventRecorder == null) { string name = eventSource.GetType().Name; throw new InvalidOperationException(String.Format( "Type <{0}> does not expose an event named \"{1}\".", name, eventName)); } return(eventRecorder); }
public void DeletingACounterShouldRaiseTheCollectionChangedEvent() { var dbfile = Path.Combine(RootPath, Guid.NewGuid().ToString("N") + ".db3"); DatabaseHelper.CreateDatabase(dbfile); var db = new DatabaseHelper(); var counter = new Counter { Name = "TestCounter", Description = "A test counter" }; var res = Task.Run(async () => { await db.AddOrUpdateCounterAsync(counter); return 0; }).Result; var eventRecorder = new EventRecorder(db, nameof(DatabaseHelper.CountersChanged)); eventRecorder.RecordEvent(); res = Task.Run(async () => { await db.DeleteCounterAsync(counter); return 0; }).Result; eventRecorder.Should().HaveCount(1); }
/// <summary> /// Generates an eventhandler for an event of type eventSignature that calls RegisterEvent on recorder /// when invoked. /// </summary> public static Delegate GenerateHandler(Type eventSignature, EventRecorder recorder) { Type returnType = GetDelegateReturnType(eventSignature); Type[] parameters = GetDelegateParameterTypes(eventSignature); Module module = recorder.GetType() .Module; var eventHandler = new DynamicMethod( eventSignature.Name + "DynamicHandler", returnType, AppendParameterListThisReference(parameters), module); MethodInfo methodToCall = typeof(EventRecorder).GetMethod(nameof(EventRecorder.RecordEvent), BindingFlags.Instance | BindingFlags.Public); ILGenerator ilGen = eventHandler.GetILGenerator(); // Make room for the one and only local variable in our function ilGen.DeclareLocal(typeof(object[])); // Create the object array for the parameters and store in local var index 0 ilGen.Emit(OpCodes.Ldc_I4, parameters.Length); ilGen.Emit(OpCodes.Newarr, typeof(object)); ilGen.Emit(OpCodes.Stloc_0); for (var index = 0; index < parameters.Length; index++) { // Push the object array onto the evaluation stack ilGen.Emit(OpCodes.Ldloc_0); // Push the array index to store our parameter in onto the evaluation stack ilGen.Emit(OpCodes.Ldc_I4, index); // Load the parameter ilGen.Emit(OpCodes.Ldarg, index + 1); // Box value-type parameters if (parameters[index].IsValueType) { ilGen.Emit(OpCodes.Box, parameters[index]); } // Store the parameter in the object array ilGen.Emit(OpCodes.Stelem_Ref); } // Push the this-reference on the stack as param 0 for calling the handler ilGen.Emit(OpCodes.Ldarg_0); // Push the object array onto the stack as param 1 for calling the handler ilGen.Emit(OpCodes.Ldloc_0); // Call the handler ilGen.EmitCall(OpCodes.Callvirt, methodToCall, null); ilGen.Emit(OpCodes.Ret); return(eventHandler.CreateDelegate(eventSignature, recorder)); }