public void AddOtherMethod_PInvokeImpl_Twice() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Abstract); EventBuilder eventBuilder = type.DefineEvent("TestEvent", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.PinvokeImpl); eventBuilder.AddOtherMethod(method); eventBuilder.AddOtherMethod(method); }
public void TestAddOtherMethodWithPInvokeMethod() { EventBuilder ev = TypeBuilder.DefineEvent("Event_PosTest4", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method = TypeBuilder.DefineMethod("Method_PosTest4", MethodAttributes.PinvokeImpl); ev.AddOtherMethod(method); // add this method again ev.AddOtherMethod(method); }
public void TestAddOtherMethodWithAbstractMethod() { EventBuilder ev = TypeBuilder.DefineEvent("Event_PosTest1", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method = TypeBuilder.DefineMethod("Method_PosTest1", MethodAttributes.Abstract | MethodAttributes.Virtual); ev.AddOtherMethod(method); // add this method again ev.AddOtherMethod(method); }
public void TestAddOtherMethodWithInstanceMethod() { EventBuilder ev = TypeBuilder.DefineEvent("Event_PosTest2", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method = TypeBuilder.DefineMethod("Method_PosTest2", MethodAttributes.Public); ILGenerator ilgen = method.GetILGenerator(); ilgen.Emit(OpCodes.Ret); ev.AddOtherMethod(method); // add this method again ev.AddOtherMethod(method); }
public void AddOtherMethod_StaticMethod_Twice() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Abstract); EventBuilder eventBuilder = type.DefineEvent("TestEvent", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Static); ILGenerator ilGenerator = method.GetILGenerator(); ilGenerator.Emit(OpCodes.Ret); eventBuilder.AddOtherMethod(method); eventBuilder.AddOtherMethod(method); }
public void TestAddOtherMethodWithStaticMethod() { byte[] bytes = new byte[MethodBodyLength]; TestLibrary.Generator.GetBytes(bytes); EventBuilder ev = TypeBuilder.DefineEvent("Event_PosTest3", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method = TypeBuilder.DefineMethod("Method_PosTest3", MethodAttributes.Static); ILGenerator ilgen = method.GetILGenerator(); ilgen.Emit(OpCodes.Ret); ev.AddOtherMethod(method); // add this method again ev.AddOtherMethod(method); }
/// <summary> /// Implements an interface event in a duck proxy type using a given type builder. /// If successful, the implemented event will be added to the given proxy member dictionary. /// </summary> /// <param name="proxyType">Type builder for the duck proxy type.</param> /// <param name="proxyMembers">Dictionary of members of the proxy type.</param> /// <param name="duckField">Field that holds a reference to the duck object to forward calls to.</param> /// <param name="interfaceEvent">The interface event to implement.</param> private void ImplementEvent(TypeBuilder proxyType, ProxyMemberDictionary proxyMembers, FieldInfo duckField, EventInfo interfaceEvent) { EventInfo duckEvent = FindDuckEvent(interfaceEvent); if (duckEvent == null) { throw new NotImplementedException("Duck type does not implement an event named \"" + interfaceEvent.Name + "\" with the same event handler type."); } EventBuilder proxyEvent = proxyType.DefineEvent(interfaceEvent.Name, EventAttributes.None, interfaceEvent.EventHandlerType); // Associated methods appear before the event in the member array; thus, they have already been // defined and implemented. The proxy member dictionary is used to refer to these. proxyEvent.SetAddOnMethod((MethodBuilder)(proxyMembers[duckEvent.GetAddMethod()])); proxyEvent.SetRemoveOnMethod((MethodBuilder)(proxyMembers[duckEvent.GetRemoveMethod()])); proxyEvent.SetRaiseMethod((MethodBuilder)(proxyMembers[duckEvent.GetRaiseMethod()])); MethodInfo[] otherDuckMethods = duckEvent.GetOtherMethods(); foreach (MethodInfo otherDuckMethod in otherDuckMethods) { if (proxyMembers.ContainsKey(otherDuckMethod)) { proxyEvent.AddOtherMethod((MethodBuilder)(proxyMembers[otherDuckMethod])); } } // Add proxy event to the proxy member dictionary // (This is not really necessary, but good to keep things consistent) // proxyMembers.Add(duckEvent, proxyEvent); // For some reason, EventBuilder does not inherit MemberInfo, so it cannot be added. }
public void AddOtherMethod_NullMethod_ThrowsArgumentNullException() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Abstract); EventBuilder eventBuilder = type.DefineEvent("TestEvent", EventAttributes.None, typeof(TestEventHandler)); AssertExtensions.Throws <ArgumentNullException>("mdBuilder", () => eventBuilder.AddOtherMethod(null)); }
public void TestCreation() { eb = tb.DefineEvent("event2", EventAttributes.SpecialName, typeof(AnEvent)); eb.SetRaiseMethod(mb); eb.SetAddOnMethod(mb); eb.SetRemoveOnMethod(mb); eb.AddOtherMethod(mb); eb.AddOtherMethod(mb); Type t = tb.CreateType(); MethodInfo mi = t.GetMethod("OnAnEvent"); EventInfo[] events = t.GetEvents(); Assert.AreEqual(2, events.Length); { EventInfo ev = t.GetEvent("event1"); Assert.AreEqual("event1", ev.Name); Assert.AreEqual(EventAttributes.None, ev.Attributes); Assert.AreEqual(t, ev.DeclaringType); Assert.AreEqual(typeof(AnEvent), ev.EventHandlerType); Assert.AreEqual(true, ev.IsMulticast); Assert.AreEqual(false, ev.IsSpecialName); Assert.AreEqual(mi, ev.GetAddMethod()); Assert.AreEqual(null, ev.GetRaiseMethod()); Assert.AreEqual(mi, ev.GetRemoveMethod()); } { EventInfo ev = t.GetEvent("event2"); Assert.AreEqual("event2", ev.Name); Assert.AreEqual(EventAttributes.SpecialName, ev.Attributes); Assert.AreEqual(t, ev.DeclaringType); Assert.AreEqual(typeof(AnEvent), ev.EventHandlerType); Assert.AreEqual(true, ev.IsMulticast); Assert.AreEqual(true, ev.IsSpecialName); Assert.AreEqual(mi, ev.GetAddMethod()); Assert.AreEqual(mi, ev.GetRaiseMethod()); Assert.AreEqual(mi, ev.GetRemoveMethod()); } }
public void AddOtherMethod_MultipleDifferentMethods() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Abstract); EventBuilder eventBuilder = type.DefineEvent("TestEvent", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method1 = type.DefineMethod("PInvokeMethod", MethodAttributes.PinvokeImpl); MethodBuilder method2 = type.DefineMethod("PublicMethod", MethodAttributes.Public); ILGenerator ilGenerator = method2.GetILGenerator(); ilGenerator.Emit(OpCodes.Ret); MethodBuilder method3 = type.DefineMethod("StaticMethod", MethodAttributes.Static); MethodBuilder method4 = type.DefineMethod("AbstractMethod", MethodAttributes.Abstract | MethodAttributes.Virtual); eventBuilder.AddOtherMethod(method1); eventBuilder.AddOtherMethod(method2); eventBuilder.AddOtherMethod(method3); eventBuilder.AddOtherMethod(method4); }
public void TestThrowsExceptionOnCreateTypeCalled() { EventBuilder ev = TypeBuilder.DefineEvent("Event_NegTest2", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method = TypeBuilder.DefineMethod("Method_NegTest2", MethodAttributes.Abstract | MethodAttributes.Virtual); TypeBuilder.CreateTypeInfo().AsType(); Assert.Throws <InvalidOperationException>(() => { ev.AddOtherMethod(method); }); }
public void TestAddOtherMethodWithMultipleMethods() { byte[] bytes = new byte[MethodBodyLength]; TestLibrary.Generator.GetBytes(bytes); EventBuilder ev = TypeBuilder.DefineEvent("Event_PosTest5", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method1 = TypeBuilder.DefineMethod("PMethod_PosTest5", MethodAttributes.PinvokeImpl); MethodBuilder method2 = TypeBuilder.DefineMethod("IMethod_PosTest5", MethodAttributes.Public); ILGenerator ilgen = method2.GetILGenerator(); ilgen.Emit(OpCodes.Ret); MethodBuilder method3 = TypeBuilder.DefineMethod("SMethod_PosTest5", MethodAttributes.Static); MethodBuilder method4 = TypeBuilder.DefineMethod("AMethod_PosTest5", MethodAttributes.Abstract | MethodAttributes.Virtual); ev.AddOtherMethod(method1); ev.AddOtherMethod(method2); ev.AddOtherMethod(method3); ev.AddOtherMethod(method4); }
public void AddOtherMethod_TypeCreated_ThrowsInvalidOperationException() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Abstract); EventBuilder eventBuilder = type.DefineEvent("TestEvent", EventAttributes.None, typeof(TestEventHandler)); MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Abstract | MethodAttributes.Virtual); type.CreateTypeInfo().AsType(); Assert.Throws <InvalidOperationException>(() => eventBuilder.AddOtherMethod(method)); }
public void TestThrowsExceptionOnNullMethod() { EventBuilder ev = TypeBuilder.DefineEvent("Event_NegTest1", EventAttributes.None, typeof(TestEventHandler)); Assert.Throws <ArgumentNullException>(() => { ev.AddOtherMethod(null); }); }
public void TestAddOtherMethod1() { eb.AddOtherMethod(null); }
/// <summary> /// Implements an interface event in a duck proxy type using a given type builder. /// If successful, the implemented event will be added to the given proxy member dictionary. /// </summary> /// <param name="proxyType">Type builder for the duck proxy type.</param> /// <param name="proxyMembers">Dictionary of members of the proxy type.</param> /// <param name="duckField">Field that holds a reference to the duck object to forward calls to.</param> /// <param name="constructorIL">IL generator to use to add code to the constructor if necessary.</param> /// <param name="interfaceEvent">The interface event to implement.</param> private void ImplementEvent(TypeBuilder proxyType, ProxyMemberDictionary proxyMembers, FieldInfo duckField, ILGenerator constructorIL, EventInfo interfaceEvent) { EventInfo duckEvent = FindDuckEvent(interfaceEvent); if (duckEvent == null) { throw new NotImplementedException("Duck type does not implement an event named \"" + interfaceEvent.Name + "\" with the same event handler type."); } EventBuilder proxyEvent = proxyType.DefineEvent(interfaceEvent.Name, EventAttributes.None, interfaceEvent.EventHandlerType); Type interfaceEventHandlerType = interfaceEvent.EventHandlerType; Type duckEventHandlerType = duckEvent.EventHandlerType; // Define event add method MethodBuilder addMethod = proxyType.DefineMethod("add_" + interfaceEvent.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis, typeof(void), new Type[] { interfaceEventHandlerType }); ILGenerator addMethodIL = addMethod.GetILGenerator(); // Define event remove method MethodBuilder removeMethod = proxyType.DefineMethod("remove_" + interfaceEvent.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis, typeof(void), new Type[] { interfaceEventHandlerType }); ILGenerator removeMethodIL = removeMethod.GetILGenerator(); if (interfaceEventHandlerType == duckEventHandlerType) { // If the event handler types are the same, we can just forward calls to add and remove like normal. MethodInfo duckAddMethod = duckEvent.GetAddMethod(); if (!duckAddMethod.IsStatic) { addMethodIL.Emit(OpCodes.Ldarg_0); addMethodIL.Emit(OpCodes.Ldfld, duckField); addMethodIL.Emit(OpCodes.Ldarg_1); addMethodIL.Emit(OpCodes.Callvirt, duckAddMethod); } else { addMethodIL.Emit(OpCodes.Ldarg_1); addMethodIL.Emit(OpCodes.Call, duckAddMethod); } MethodInfo duckRemoveMethod = duckEvent.GetRemoveMethod(); if (!duckRemoveMethod.IsStatic) { removeMethodIL.Emit(OpCodes.Ldarg_0); removeMethodIL.Emit(OpCodes.Ldfld, duckField); removeMethodIL.Emit(OpCodes.Ldarg_1); removeMethodIL.Emit(OpCodes.Callvirt, duckRemoveMethod); } else { removeMethodIL.Emit(OpCodes.Ldarg_1); removeMethodIL.Emit(OpCodes.Call, duckRemoveMethod); } } else { // If the event handler types are different, we need some special behavior. Specifically, the event handlers // added using the interface are kept as a seperate multicast delegate in the proxy class and an event handler // is added to the duck that calls the proxy event delegate. // Define the event multicast delegate field FieldBuilder eventHandlerField = proxyType.DefineField(interfaceEvent.Name, interfaceEventHandlerType, FieldAttributes.Private); // Implement the add method addMethodIL.Emit(OpCodes.Ldarg_0); addMethodIL.Emit(OpCodes.Ldarg_0); addMethodIL.Emit(OpCodes.Ldfld, eventHandlerField); addMethodIL.Emit(OpCodes.Ldarg_1); addMethodIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { typeof(Delegate), typeof(Delegate) })); addMethodIL.Emit(OpCodes.Castclass, interfaceEventHandlerType); addMethodIL.Emit(OpCodes.Stfld, eventHandlerField); // Implement the remove method removeMethodIL.Emit(OpCodes.Ldarg_0); removeMethodIL.Emit(OpCodes.Ldarg_0); removeMethodIL.Emit(OpCodes.Ldfld, eventHandlerField); removeMethodIL.Emit(OpCodes.Ldarg_1); removeMethodIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { typeof(Delegate), typeof(Delegate) })); removeMethodIL.Emit(OpCodes.Castclass, interfaceEventHandlerType); removeMethodIL.Emit(OpCodes.Stfld, eventHandlerField); // Set some local variables for later use... MethodInfo interfaceInvokeMethod = interfaceEventHandlerType.GetMethod("Invoke"); Type[] interfaceInvokeMethodParameterTypes = GetParameterTypes(interfaceInvokeMethod.GetParameters()); MethodInfo duckInvokeMethod = duckEventHandlerType.GetMethod("Invoke"); Type[] duckInvokeMethodParameterTypes = GetParameterTypes(duckInvokeMethod.GetParameters()); // Define the method that will serve as an event handler to the duck which will invoke the proxy's delegate MethodBuilder proxyInvokeMethod = proxyType.DefineMethod("Invoke" + interfaceEvent.Name, MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis, duckInvokeMethod.ReturnType, duckInvokeMethodParameterTypes); ILGenerator proxyInvokeMethodIL = proxyInvokeMethod.GetILGenerator(); // First, check if the proxy event handler is null Label ifEventHandlerIsNullLabel = proxyInvokeMethodIL.DefineLabel(); proxyInvokeMethodIL.Emit(OpCodes.Ldarg_0); proxyInvokeMethodIL.Emit(OpCodes.Ldfld, eventHandlerField); proxyInvokeMethodIL.Emit(OpCodes.Ldnull); proxyInvokeMethodIL.Emit(OpCodes.Ceq); proxyInvokeMethodIL.Emit(OpCodes.Brtrue_S, ifEventHandlerIsNullLabel); // If the proxy event handler is not null, invoke it proxyInvokeMethodIL.Emit(OpCodes.Ldarg_0); proxyInvokeMethodIL.Emit(OpCodes.Ldfld, eventHandlerField); for (int i = 0; i < interfaceInvokeMethodParameterTypes.Length; i++) { proxyInvokeMethodIL.Emit(OpCodes.Ldarg, i + 1); DuckTyping.EmitCastIL(proxyInvokeMethodIL, interfaceInvokeMethodParameterTypes[i], duckInvokeMethodParameterTypes[i]); } proxyInvokeMethodIL.Emit(OpCodes.Callvirt, interfaceInvokeMethod); // If the proxy event handler is null, execution jumps here proxyInvokeMethodIL.MarkLabel(ifEventHandlerIsNullLabel); // Return proxyInvokeMethodIL.Emit(OpCodes.Ret); // Add code to the constructor to add the event handler to the duck. MethodInfo duckAddMethod = duckEvent.GetAddMethod(); if (!duckAddMethod.IsStatic) { constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldfld, duckField); } constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldftn, proxyInvokeMethod); constructorIL.Emit(OpCodes.Newobj, duckEventHandlerType.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })); if (!duckAddMethod.IsStatic) { constructorIL.Emit(OpCodes.Callvirt, duckAddMethod); } else { constructorIL.Emit(OpCodes.Call, duckAddMethod); } } // Finish add method and set it for the event addMethodIL.Emit(OpCodes.Ret); proxyEvent.SetAddOnMethod(addMethod); // Finish remove method and set it for the event removeMethodIL.Emit(OpCodes.Ret); proxyEvent.SetRemoveOnMethod(removeMethod); // Other associated methods appear before the event in the member array; thus, they have already been // defined and implemented. The proxy member dictionary is used to refer to these. MethodInfo raiseMethod = duckEvent.GetRaiseMethod(); if (raiseMethod != null) { proxyEvent.SetRaiseMethod((MethodBuilder)(proxyMembers[raiseMethod])); } MethodInfo[] otherDuckMethods = duckEvent.GetOtherMethods(); foreach (MethodInfo otherDuckMethod in otherDuckMethods) { if (proxyMembers.ContainsKey(otherDuckMethod)) { proxyEvent.AddOtherMethod((MethodBuilder)(proxyMembers[otherDuckMethod])); } } // Add proxy event to the proxy member dictionary // (This is not really necessary, but good to keep things consistent) // if (proxyMembers != null) proxyMembers[duckEvent] = proxyEvent; // For some reason, EventBuilder does not inherit MemberInfo, so it cannot be added. }