/// <summary> /// Intializes a new instance of the <see cref="GeneratedProperty"/> class (for overrides). /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="property">Inherited property to override.</param> /// <param name="implementation">Implementation strategy to use (may be null).</param> internal GeneratedProperty( CodeGenEngine engine, InheritedProperty property, IPropertyImplementation implementation) : base(engine) { // check parameters if (property == null) { throw new ArgumentNullException("property"); } mName = property.Name; mKind = PropertyKind.Override; mType = property.Type; mGetAccessorMethod = engine.AddOverride(property.GetAccessor); mSetAccessorMethod = engine.AddOverride(property.SetAccessor); mImplementation = implementation; if (mImplementation != null) { mImplementation.Declare(engine, this); } // do not allow changes to overridden properties // (signature must match the signature of the inherited property) Freeze(); }
/// <summary> /// Intializes a new instance of the <see cref="GeneratedField{T}"/> class (with default value). /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="isStatic">true to emit a static field; false to emit a member field.</param> /// <param name="name">Name of the field (null to create an anonymous field).</param> /// <param name="visibility">Visibility of the field.</param> /// <param name="defaultValue">Default value of the field.</param> internal GeneratedField(CodeGenEngine engine, bool isStatic, string name, Visibility visibility, T defaultValue) : base(engine) { // ensure that the specified type is public and all nested types are public, too // => otherwise the dynamically created assembly is not able to access it CodeGenHelpers.CheckTypeIsTotallyPublic(typeof(T)); // ensure that the specified default value is of the same type as the field if (!typeof(T).IsAssignableFrom(defaultValue.GetType())) { string error = string.Format("Default value ({0}) is not assignable to field ({1}) of type ({2}).", defaultValue, name, typeof(T).FullName); throw new ArgumentException(error); } // determine the initializer that pushes the default value into the field at runtime if (!FieldInitializers.Default.TryGetValue(typeof(T), out mInitializer)) { string error = string.Format("Default value ({0}) not supported for field ({1}).", defaultValue, name); throw new NotSupportedException(error); } mVisibility = visibility; mInitialValueFactory = null; mDefaultValue = defaultValue; mIsStatic = isStatic; mName = name; if (string.IsNullOrWhiteSpace(mName)) { mName = (isStatic ? "s" : "m") + "X" + Guid.NewGuid().ToString("N"); } }
/// <summary> /// Intializes a new instance of the <see cref="InheritedMethod"/> class. /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="method">Method the type in creation has inherited.</param> internal InheritedMethod(CodeGenEngine engine, MethodInfo method) : base(engine) { mMethodInfo = method; mAccessModifier = mMethodInfo.ToVisibility(); mParameterTypes = mMethodInfo.GetParameters().Select(x => x.ParameterType).ToArray(); Freeze(); }
/// <summary> /// Intializes a new instance of the <see cref="InheritedEvent"/> class. /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="eventInfo">Event the type in creation has inherited.</param> internal InheritedEvent(CodeGenEngine engine, EventInfo eventInfo) : base(engine) { mEventInfo = eventInfo; mAddAccessor = new InheritedMethod(engine, mEventInfo.GetAddMethod(true)); mRemoveAccessor = new InheritedMethod(engine, mEventInfo.GetRemoveMethod(true)); Freeze(); }
public void AddEvents_UsingBuiltinImplementation_Standard() { // create the type ClassDefinition classDefinition = new ClassDefinition("MyClass"); classDefinition.AddModule(new TestModule_AddEvent_UsingBuiltinImplementation_Standard()); Type classType = CodeGenEngine.CreateClass(classDefinition); Assert.NotNull(classType); Assert.Equal(typeof(object), classType.BaseType); Assert.Equal("MyClass", classType.Name); // instantiate the type dynamic obj = Activator.CreateInstance(classType); Assert.NotNull(obj); // event type: System.EventHandler EventHandler handler1 = (sender, e) => { Assert.Same(obj, sender); Assert.Same(EventArgs.Empty, e); }; obj.NonGeneric += handler1; obj.OnNonGeneric(); obj.NonGeneric -= handler1; // event type: System.EventHandler<T> with T == System.EventArgs EventHandler <EventArgs> handler2 = (sender, e) => { Assert.Same(obj, sender); Assert.Same(EventArgs.Empty, e); }; obj.GenericBasic += handler2; obj.OnGenericBasic(); obj.GenericBasic -= handler2; // event type: System.EventHandler<T> with T derived from System.EventArgs SpecializedEventArgs e3 = new SpecializedEventArgs(); EventHandler <SpecializedEventArgs> handler3 = (sender, e) => { Assert.Same(obj, sender); Assert.Same(e3, e); }; obj.GenericSpecialized += handler3; obj.OnGenericSpecialized(e3); obj.GenericSpecialized -= handler3; // event type: custom delegate type SpecialDelegateEventHandler handler4 = (s, x) => { Assert.Equal("test", s); Assert.Equal(42, x); }; obj.Special += handler4; obj.OnSpecial("test", 42); obj.Special -= handler4; }
[InlineData(null)] // random class name public void GenerateEmptyClass_DerivedFromClassWithoutParameterlessConstructor(string className) { Assert.Throws <CodeGenException>(() => { // should throw an exception, because the base class does not have a parameterless constructor ClassDefinition classDefinition = new ClassDefinition(typeof(ClassWithoutParameterlessConstructor), false, className); CodeGenEngine.CreateClass(classDefinition); }); }
public void AddField_WithDefaultValue(Visibility visibility, Type fieldType, object defaultValue) { // generate the field name string fieldName = "m" + fieldType.Name; // setup code generation module CallbackCodeGenModule module = new CallbackCodeGenModule(); module.Declare = (m) => { MethodInfo genericMethod = typeof(CodeGenEngine) .GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(x => x.Name == "AddField" && x.IsGenericMethodDefinition && x.GetGenericArguments().Length == 1) .Where(x => x.GetParameters().Select(y => y.ParameterType).SequenceEqual(new[] { typeof(string), typeof(Visibility), x.GetGenericArguments()[0] })) .Single(); MethodInfo method = genericMethod.MakeGenericMethod(fieldType); method.Invoke(m.Engine, new object[] { fieldName, visibility, defaultValue }); }; // create the type ClassDefinition classDefinition = new ClassDefinition("MyClass"); classDefinition.AddModule(module); Type classType = CodeGenEngine.CreateClass(classDefinition); Assert.NotNull(classType); Assert.Equal(typeof(object), classType.BaseType); Assert.Equal("MyClass", classType.Name); // check whether the field was generated correctly var field = classType.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(field); Assert.Equal(fieldType, field.FieldType); Assert.Equal(visibility, field.ToVisibility()); // instantiate the type dynamic obj = Activator.CreateInstance(classType); Assert.NotNull(obj); // check whether fields have a value of the expected type and default type var fieldValue = GetFieldValue(obj, fieldName); Assert.Equal(defaultValue, fieldValue); if (defaultValue != null) { // the type of the field must match the type of the default value Assert.IsType(defaultValue.GetType(), fieldValue); // if the field type is a reference type, the value must actually be the same... if (!fieldType.IsValueType) { Assert.Same(defaultValue, fieldValue); } } }
public void GetAbstractProperties() { // create the type ClassDefinition classDefinition = new ClassDefinition(typeof(GetAbstractPropertiesClassC), false, "MyClass"); classDefinition.AddModule(new TestModule_GetAbstractProperties()); Type classType = CodeGenEngine.CreateClass(classDefinition); Assert.NotNull(classType); Assert.Equal(typeof(GetAbstractPropertiesClassC), classType.BaseType); Assert.Equal("MyClass", classType.Name); }
/// <summary> /// Implements the event. /// </summary> /// <param name="engine">The <see cref="CodeGenEngine"/> assembling the type in creation.</param> /// <param name="property">The property to implement.</param> public void Implement(CodeGenEngine engine, GeneratedProperty property) { ILGenerator getMsil = property.GetAccessor.MethodBuilder?.GetILGenerator(); ILGenerator setMsil = property.SetAccessor.MethodBuilder?.GetILGenerator(); // implement get accessor // --------------------------------------------------------------------------------------------------------------- if (getMsil != null) { MethodInfo getValueMethod = typeof(System.Windows.DependencyObject).GetMethod("GetValue", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(System.Windows.DependencyProperty) }, null); getMsil.Emit(OpCodes.Ldarg_0); if (mDependencyProperty.IsReadOnly) { getMsil.Emit(OpCodes.Ldsfld, mDependencyProperty.DependencyPropertyField.FieldBuilder); PropertyInfo dependencyPropertyProperty = typeof(System.Windows.DependencyPropertyKey).GetProperty("DependencyProperty"); getMsil.Emit(OpCodes.Call, dependencyPropertyProperty.GetGetMethod(false)); } else { getMsil.Emit(OpCodes.Ldsfld, mDependencyProperty.DependencyPropertyField.FieldBuilder); } getMsil.Emit(OpCodes.Call, getValueMethod); if (property.Type.IsValueType) { getMsil.Emit(OpCodes.Unbox_Any, property.Type); } getMsil.Emit(OpCodes.Ret); } // implement set accessor // --------------------------------------------------------------------------------------------------------------- if (setMsil != null) { MethodInfo setValueMethod = mDependencyProperty.IsReadOnly ? typeof(System.Windows.DependencyObject).GetMethod("SetValue", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(System.Windows.DependencyPropertyKey), typeof(object) }, null) : typeof(System.Windows.DependencyObject).GetMethod("SetValue", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(System.Windows.DependencyProperty), typeof(object) }, null); setMsil.Emit(OpCodes.Ldarg_0); setMsil.Emit(OpCodes.Ldsfld, mDependencyProperty.DependencyPropertyField.FieldBuilder); if (property.Type.IsValueType) { setMsil.Emit(OpCodes.Box, property.Type); } setMsil.Emit(OpCodes.Call, setValueMethod); } }
public void AddStaticField_WithInitializer(Visibility visibility, Type fieldType, object expectedValue, FieldInitializer initializer) { // generate the field name string fieldName = "s" + fieldType.Name; // setup code generation module CallbackCodeGenModule module = new CallbackCodeGenModule(); module.Declare = (m) => { MethodInfo genericMethod = typeof(CodeGenEngine) .GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(x => x.Name == "AddStaticField" && x.IsGenericMethodDefinition && x.GetGenericArguments().Length == 1) .Where(x => x.GetParameters().Select(y => y.ParameterType).SequenceEqual(new[] { typeof(string), typeof(Visibility), typeof(FieldInitializer) })) .Single(); MethodInfo method = genericMethod.MakeGenericMethod(fieldType); method.Invoke(m.Engine, new object[] { fieldName, visibility, initializer }); }; // create the type ClassDefinition classDefinition = new ClassDefinition("MyClass"); classDefinition.AddModule(module); Type classType = CodeGenEngine.CreateClass(classDefinition); Assert.NotNull(classType); Assert.Equal(typeof(object), classType.BaseType); Assert.Equal("MyClass", classType.Name); // check whether the field was generated correctly var field = classType.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); Assert.NotNull(field); Assert.Equal(fieldType, field.FieldType); Assert.Equal(visibility, field.ToVisibility()); // instantiate the type dynamic obj = Activator.CreateInstance(classType); Assert.NotNull(obj); // check whether fields have a value of the expected type and default type var fieldValue = GetStaticFieldValue(classType, fieldName); Assert.Equal(expectedValue, fieldValue); }
public void AddStaticField_WithFactoryMethod_Class(Visibility visibility) { // generate the field name string fieldName = "sField"; // setup code generation module CallbackCodeGenModule module = new CallbackCodeGenModule(); module.Declare = (m) => { m.Engine.AddStaticField <DemoClass>(fieldName, visibility, () => new DemoClass() { MyInt32 = 42, MyString = "Lorem Ipsum" }); }; // create the type ClassDefinition classDefinition = new ClassDefinition("MyClass"); classDefinition.AddModule(module); Type classType = CodeGenEngine.CreateClass(classDefinition); Assert.NotNull(classType); Assert.Equal(typeof(object), classType.BaseType); Assert.Equal("MyClass", classType.Name); // check whether the field was generated correctly var field = classType.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); Assert.NotNull(field); Assert.Equal(typeof(DemoClass), field.FieldType); Assert.Equal(visibility, field.ToVisibility()); // instantiate the type object obj = Activator.CreateInstance(classType); Assert.NotNull(obj); // check whether the field has the expected value var fieldValue = GetStaticFieldValue(classType, fieldName); Assert.NotNull(fieldValue); Assert.IsType <DemoClass>(fieldValue); Assert.Equal(42, ((DemoClass)fieldValue).MyInt32); Assert.Equal("Lorem Ipsum", ((DemoClass)fieldValue).MyString); }
/// <summary> /// Intializes a new instance of the <see cref="GeneratedMethod"/> class. /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="kind">Kind of method determining whether the method is static, abstract, virtual or an override.</param> /// <param name="name">Name of the method.</param> /// <param name="returnType">Return type of the method.</param> /// <param name="parameterTypes">Types of the method parameters.</param> /// <param name="visibility">Visibility of the method.</param> internal GeneratedMethod( CodeGenEngine engine, MethodKind kind, string name, Type returnType, Type[] parameterTypes, Visibility visibility) : base(engine) { // check parameters if (name != null) { CheckIdentifier(name); } if (returnType == null) { throw new ArgumentNullException(nameof(returnType)); } CodeGenHelpers.CheckTypeIsTotallyPublic(returnType); if (parameterTypes == null) { throw new ArgumentNullException(nameof(parameterTypes)); } if (parameterTypes.Any(x => x == null)) { throw new ArgumentException("List of parameter types contains a null reference."); } foreach (Type type in parameterTypes) { CodeGenHelpers.CheckTypeIsTotallyPublic(type); } // generate random name, if no name was specified if (name == null || name.Trim().Length == 0) { name = "X" + Guid.NewGuid().ToString("N"); } mKind = kind; mName = name; mReturnType = returnType; mParameterTypes = new List <Type>(parameterTypes); mVisibility = visibility; mCallingConvention = kind.ToCallingConvention(false); UpdateEffectiveMethodAttributes(); }
[InlineData(null, true)] // random class name, create pass-through constructors public void GenerateEmptyClass_DerivedFromClassWithParameterlessConstructor(string className, bool createPassThroughConstructors) { // create the type ClassDefinition classDefinition = new ClassDefinition(typeof(ClassWithParameterlessConstructor), createPassThroughConstructors, "MyClass"); Type classType = CodeGenEngine.CreateClass(classDefinition); Assert.NotNull(classType); Assert.Equal(typeof(ClassWithParameterlessConstructor), classType.BaseType); if (className != null) { Assert.Equal(className, classType.Name); } // instantiate the type dynamic obj = Activator.CreateInstance(classType); Assert.NotNull(obj); }
[InlineData(null)] // random class name public void GenerateEmptyClass(string className) { // create the type ClassDefinition classDefinition = new ClassDefinition(className); Type classType = CodeGenEngine.CreateClass(classDefinition); Assert.NotNull(classType); Assert.Equal(typeof(object), classType.BaseType); if (className != null) { Assert.Equal(className, classType.Name); } // instantiate the type dynamic obj = Activator.CreateInstance(classType); Assert.NotNull(obj); }
/// <summary> /// Intializes a new instance of the <see cref="GeneratedField{T}"/> class (with custom initializer). /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="isStatic">true to emit a static field; false to emit a member field.</param> /// <param name="name">Name of the field (null to create an anonymous field).</param> /// <param name="visibility">Visibility of the field.</param> /// <param name="initializer">Field initializer that emits code to intitialize the field.</param> internal GeneratedField(CodeGenEngine engine, bool isStatic, string name, Visibility visibility, FieldInitializer initializer) : base(engine) { // ensure that the specified type is public and all nested types are public, too // => otherwise the dynamically created assembly is not able to access it CodeGenHelpers.CheckTypeIsTotallyPublic(typeof(T)); mVisibility = visibility; mInitializer = initializer; mInitialValueFactory = null; mDefaultValue = default(T); mIsStatic = isStatic; mName = name; if (string.IsNullOrWhiteSpace(mName)) { mName = (isStatic ? "s" : "m") + "X" + Guid.NewGuid().ToString("N"); } }
/// <summary> /// Implements the event. /// </summary> /// <param name="engine">The <see cref="CodeGenEngine"/> assembling the type in creation.</param> /// <param name="property">The property to implement.</param> public void Implement(CodeGenEngine engine, GeneratedProperty property) { ILGenerator getMsil = property.GetAccessor.MethodBuilder?.GetILGenerator(); ILGenerator setMsil = property.SetAccessor.MethodBuilder?.GetILGenerator(); // implement get accessor // --------------------------------------------------------------------------------------------------------------- if (getMsil != null) { if (property.Kind == PropertyKind.Static) { getMsil.Emit(OpCodes.Ldsfld, mBackingField.FieldBuilder); } else { getMsil.Emit(OpCodes.Ldarg_0); getMsil.Emit(OpCodes.Ldfld, mBackingField.FieldBuilder); } getMsil.Emit(OpCodes.Ret); } // implement set accessor // --------------------------------------------------------------------------------------------------------------- if (setMsil != null) { if (property.Kind == PropertyKind.Static) { setMsil.Emit(OpCodes.Ldarg_0); setMsil.Emit(OpCodes.Stsfld, mBackingField.FieldBuilder); } else { setMsil.Emit(OpCodes.Ldarg_0); setMsil.Emit(OpCodes.Ldarg_1); setMsil.Emit(OpCodes.Stfld, mBackingField.FieldBuilder); } setMsil.Emit(OpCodes.Ret); } }
/// <summary> /// Intializes a new instance of the <see cref="GeneratedProperty"/> class. /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="kind">Kind of property to generate.</param> /// <param name="type">Type of the property.</param> /// <param name="name">Name of the property (may be null).</param> /// <param name="implementation">Implementation strategy to use (may be null).</param> internal GeneratedProperty( CodeGenEngine engine, PropertyKind kind, Type type, string name, IPropertyImplementation implementation) : base(engine) { // check parameters if (type == null) { throw new ArgumentNullException("type"); } // ensure that the specified type is public and all nested types are public, too // => otherwise the dynamically created assembly is not able to access it CodeGenHelpers.CheckTypeIsTotallyPublic(type); mName = name; mKind = kind; mType = type; if (mName == null || mName.Trim().Length == 0) { mName = "X" + Guid.NewGuid().ToString("N"); } // declare the 'get' accessor method mGetAccessorMethod = engine.AddMethod(kind.ToMethodKind(), "get_" + name, type, Type.EmptyTypes, Visibility.Public); mGetAccessorMethod.AdditionalMethodAttributes = MethodAttributes.SpecialName | MethodAttributes.HideBySig; // declare the 'set' accessor method mSetAccessorMethod = engine.AddMethod(kind.ToMethodKind(), "set_" + name, typeof(void), new Type[] { type }, Visibility.Public); mSetAccessorMethod.AdditionalMethodAttributes = MethodAttributes.SpecialName | MethodAttributes.HideBySig; mImplementation = implementation; if (mImplementation != null) { mImplementation.Declare(engine, this); } }
/// <summary> /// Intializes a new instance of the <see cref="GeneratedProperty"/> class. /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="property">Property the type in creation has inherited.</param> internal InheritedProperty(CodeGenEngine engine, PropertyInfo property) : base(engine) { mPropertyInfo = property; // init get accessor method MethodInfo getAccessor = mPropertyInfo.GetGetMethod(true); if (getAccessor != null) { mGetAccessorMethod = new InheritedMethod(engine, getAccessor); } // init set accessor method MethodInfo setAccessor = mPropertyInfo.GetSetMethod(true); if (setAccessor != null) { mSetAccessorMethod = new InheritedMethod(engine, setAccessor); } Freeze(); }
/// <summary> /// Intializes a new instance of the <see cref="GeneratedMethod"/> class (for overrides). /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="method">Inherited method to override.</param> internal GeneratedMethod(CodeGenEngine engine, InheritedMethod method) : base(engine) { if (method == null) { throw new ArgumentNullException(nameof(method)); } mName = method.Name; mKind = MethodKind.Override; mReturnType = method.ReturnType; mParameterTypes = new List <Type>(method.ParameterTypes); mVisibility = method.Visibility; mCallingConvention = method.MethodInfo.CallingConvention; mMethodAttributes = method.MethodInfo.Attributes; mMethodAttributes &= ~MethodAttributes.Abstract; mMethodAttributes &= ~MethodAttributes.NewSlot; mMethodAttributes |= MethodAttributes.ReuseSlot; // do not allow changes to overridden methods // (signature must match the signature of the inherited method) Freeze(); }
public void AddStaticEvent_UsingBuiltinImplementation_Standard() { // create the type ClassDefinition classDefinition = new ClassDefinition("MyClass"); classDefinition.AddModule(new TestModule_AddStaticEvent_UsingBuiltinImplementation_Standard()); Type classType = CodeGenEngine.CreateClass(classDefinition); Assert.NotNull(classType); Assert.Equal(typeof(object), classType.BaseType); Assert.Equal("MyClass", classType.Name); // event type: System.EventHandler // ---------------------------------------------------------------------------------- EventHandler handler1 = (sender, e) => { Assert.Null(sender); Assert.Same(EventArgs.Empty, e); }; EventInfo eventInfo1 = classType.GetEvent("NonGeneric"); eventInfo1.AddEventHandler(null, handler1); MethodInfo eventRaiser1 = classType.GetMethod("OnNonGeneric"); eventRaiser1.Invoke(null, Type.EmptyTypes); eventInfo1.RemoveEventHandler(null, handler1); // event type: System.EventHandler<T> with T == System.EventArgs // ---------------------------------------------------------------------------------- EventHandler <EventArgs> handler2 = (sender, e) => { Assert.Null(sender); Assert.Same(EventArgs.Empty, e); }; EventInfo eventInfo2 = classType.GetEvent("GenericBasic"); eventInfo2.AddEventHandler(null, handler2); MethodInfo eventRaiser2 = classType.GetMethod("OnGenericBasic"); eventRaiser2.Invoke(null, Type.EmptyTypes); eventInfo2.RemoveEventHandler(null, handler2); // event type: System.EventHandler<T> with T derived from System.EventArgs // ---------------------------------------------------------------------------------- SpecializedEventArgs e3 = new SpecializedEventArgs(); EventHandler <SpecializedEventArgs> handler3 = (sender, e) => { Assert.Null(sender); Assert.Same(e3, e); }; EventInfo eventInfo3 = classType.GetEvent("GenericSpecialized"); eventInfo3.AddEventHandler(null, handler3); MethodInfo eventRaiser3 = classType.GetMethod("OnGenericSpecialized"); eventRaiser3.Invoke(null, new object[] { e3 }); eventInfo3.RemoveEventHandler(null, handler3); // event type: custom delegate type // ---------------------------------------------------------------------------------- SpecialDelegateEventHandler handler4 = (s, x) => { Assert.Equal("test", s); Assert.Equal(42, x); }; EventInfo eventInfo4 = classType.GetEvent("Special"); eventInfo4.AddEventHandler(null, handler4); MethodInfo eventRaiser4 = classType.GetMethod("OnSpecial"); eventRaiser4.Invoke(null, new object[] { "test", 42 }); eventInfo4.RemoveEventHandler(null, handler4); }
/// <summary> /// Is called when the event the implementation strategy is attached to is removed from the type in creation. /// </summary> /// <param name="engine">The <see cref="CodeGenEngine"/> assembling the type in creation.</param> public void OnRemoving(CodeGenEngine engine) { engine.RemoveField(mBackingField); }
/// <summary> /// Reviews the default declaration of the event and adds additional type declarations, if necessary. /// </summary> /// <param name="engine">The <see cref="CodeGenEngine"/> assembling the type in creation.</param> /// <param name="evnt">The event to review.</param> public void Declare(CodeGenEngine engine, GeneratedEvent evnt) { // declare the backing field storing event handlers mBackingField = engine.AddField(evnt.Type, null, evnt.Kind == EventKind.Static, evnt.Visibility, null); }
/// <summary> /// Intializes a new instance of the <see cref="GeneratedField{T}"/> class (without default value). /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="isStatic">true to emit a static field; false to emit a member field.</param> /// <param name="name">Name of the field (null to create an anonymous field).</param> /// <param name="visibility">Visibility of the field.</param> internal GeneratedField(CodeGenEngine engine, bool isStatic, string name, Visibility visibility) : this(engine, isStatic, name, visibility, null) { }
/// <summary> /// Is called by <see cref="CodeGenEngine"/> when it starts processing. /// </summary> void ICodeGenModule.Initialize(CodeGenEngine engine) { mEngine = engine; OnInitialize(); }
/// <summary> /// Is called by <see cref="CodeGenEngine"/> when processing has finished. /// </summary> void ICodeGenModule.Cleanup() { mEngine = null; OnCleanup(); }
/// <summary> /// Intializes a new instance of the <see cref="GeneratedEvent"/> class. /// </summary> /// <param name="engine">The code generation engine.</param> /// <param name="kind">Kind of the event.</param> /// <param name="eventType">Type of the event (must be a delegate type).</param> /// <param name="eventName">Name of the event (may be null).</param> /// <param name="visibility">Access modifier defining the visibility of the event.</param> /// <param name="eventRaiserName">Name of the event raiser method (may be null).</param> /// <param name="implementation">Implementation strategy to use (may be null).</param> internal GeneratedEvent( CodeGenEngine engine, EventKind kind, Type eventType, string eventName, Visibility visibility, string eventRaiserName, IEventImplementation implementation) : base(engine) { if (!typeof(Delegate).IsAssignableFrom(eventType)) { string error = string.Format("The specified type ({0}) is not a delegate type and can therefore not be used for an event.", eventType.FullName); throw new ArgumentException(error); } // ensure that the specified event handler type is public and all nested types are public, too // => otherwise the dynamically created assembly is not able to access it CodeGenHelpers.CheckTypeIsTotallyPublic(eventType); mKind = kind; mType = eventType; mName = eventName; if (mName == null || mName.Trim().Length == 0) { mName = "X" + Guid.NewGuid().ToString("N"); } if (string.IsNullOrWhiteSpace(eventRaiserName)) { eventRaiserName = "On" + mName; } // add 'add' accessor method mAddAccessorMethod = Engine.AddMethod(mKind.ToMethodKind(), "add_" + mName, typeof(void), new Type[] { mType }, visibility); mAddAccessorMethod.AdditionalMethodAttributes = MethodAttributes.SpecialName | MethodAttributes.HideBySig; // add 'remove' accessor method mRemoveAccessorMethod = Engine.AddMethod(mKind.ToMethodKind(), "remove_" + mName, typeof(void), new Type[] { mType }, visibility); mRemoveAccessorMethod.AdditionalMethodAttributes = MethodAttributes.SpecialName | MethodAttributes.HideBySig; // add event raiser method MethodKind raiserMethodKind = mKind == EventKind.Static ? MethodKind.Static : MethodKind.Normal; Type[] raiserParameterTypes; if (mType == typeof(EventHandler) || mType == typeof(EventHandler <EventArgs>)) { // System.EventHandler // System.EventHandler<EventArgs> raiserParameterTypes = Type.EmptyTypes; } else if (mType.IsGenericType && mType.GetGenericTypeDefinition() == typeof(EventHandler <>)) { // EventHandler<T> with T derived from System.EventArgs raiserParameterTypes = mType.GetGenericArguments(); } else if (typeof(Delegate).IsAssignableFrom(mType)) { MethodInfo invokeMethod = mType.GetMethod("Invoke"); raiserParameterTypes = invokeMethod.GetParameters().Select(x => x.ParameterType).ToArray(); } else { throw new NotSupportedException("The event type is not supported."); } mRaiserMethod = Engine.AddMethod(raiserMethodKind, eventRaiserName, typeof(void), raiserParameterTypes, Visibility.Protected); // call implementation strategy mImplementation = implementation; if (mImplementation != null) { mImplementation.Declare(engine, this); } }
/// <summary> /// Reviews the declaration of the property and adds additional type declarations, if necessary. /// </summary> /// <param name="engine">The <see cref="CodeGenEngine"/> assembling the type in creation.</param> /// <param name="property">The property to review.</param> public void Declare(CodeGenEngine engine, GeneratedProperty property) { }
/// <summary> /// Implements the event. /// </summary> /// <param name="engine">The <see cref="CodeGenEngine"/> assembling the type in creation.</param> /// <param name="property">The property to implement.</param> public void Implement(CodeGenEngine engine, GeneratedProperty property) { ILGenerator getMsil = property.GetAccessor.MethodBuilder?.GetILGenerator(); ILGenerator setMsil = property.SetAccessor.MethodBuilder?.GetILGenerator(); // implement get accessor // --------------------------------------------------------------------------------------------------------------- if (getMsil != null) { if (property.Kind == PropertyKind.Static) { getMsil.Emit(OpCodes.Ldsfld, mBackingField.FieldBuilder); } else { getMsil.Emit(OpCodes.Ldarg_0); getMsil.Emit(OpCodes.Ldfld, mBackingField.FieldBuilder); } getMsil.Emit(OpCodes.Ret); } // implement set accessor // --------------------------------------------------------------------------------------------------------------- if (setMsil != null) { MethodInfo equalsMethod = typeof(object).GetMethod("Equals", new Type[] { typeof(object), typeof(object) }); Label endLabel = setMsil.DefineLabel(); // jump to end, if the value to set equals the backing field if (property.Kind == PropertyKind.Static) { setMsil.Emit(OpCodes.Ldsfld, mBackingField.FieldBuilder); if (property.Type.IsValueType) { setMsil.Emit(OpCodes.Box, property.Type); } setMsil.Emit(OpCodes.Ldarg_0); if (property.Type.IsValueType) { setMsil.Emit(OpCodes.Box, property.Type); } } else { setMsil.Emit(OpCodes.Ldarg_0); setMsil.Emit(OpCodes.Ldfld, mBackingField.FieldBuilder); if (property.Type.IsValueType) { setMsil.Emit(OpCodes.Box, property.Type); } setMsil.Emit(OpCodes.Ldarg_1); if (property.Type.IsValueType) { setMsil.Emit(OpCodes.Box, property.Type); } } setMsil.Emit(OpCodes.Call, equalsMethod); setMsil.Emit(OpCodes.Brtrue_S, endLabel); // update field if (property.Kind == PropertyKind.Static) { setMsil.Emit(OpCodes.Ldarg_0); setMsil.Emit(OpCodes.Stsfld, mBackingField.FieldBuilder); } else { setMsil.Emit(OpCodes.Ldarg_0); setMsil.Emit(OpCodes.Ldarg_1); setMsil.Emit(OpCodes.Stfld, mBackingField.FieldBuilder); } // call event raiser if (property.Kind != PropertyKind.Static) { IMethod raiserMethod = engine.GetMethod("OnPropertyChanged", new Type[] { typeof(string) }); if (raiserMethod == null) { string error = string.Format( "The class ({0}) or its base class ({1}) does not define 'void OnPropertyChanged(string name)'.", engine.TypeBuilder.FullName, engine.TypeBuilder.BaseType.FullName); sLog.Write(LogLevel.Error, error); throw new CodeGenException(error); } if (raiserMethod is GeneratedMethod) { GeneratedMethod method = raiserMethod as GeneratedMethod; setMsil.Emit(OpCodes.Ldarg_0); setMsil.Emit(OpCodes.Ldstr, property.Name); setMsil.Emit(OpCodes.Callvirt, method.MethodBuilder); if (method.ReturnType != typeof(void)) { setMsil.Emit(OpCodes.Pop); } } else if (raiserMethod is InheritedMethod) { InheritedMethod method = raiserMethod as InheritedMethod; setMsil.Emit(OpCodes.Ldarg_0); setMsil.Emit(OpCodes.Ldstr, property.Name); setMsil.Emit(OpCodes.Callvirt, method.MethodInfo); if (method.ReturnType != typeof(void)) { setMsil.Emit(OpCodes.Pop); } } else { throw new NotImplementedException("Method is neither generated nor inherited."); } } setMsil.MarkLabel(endLabel); setMsil.Emit(OpCodes.Ret); } }
/// <summary> /// Implements the event. /// </summary> /// <param name="engine">The <see cref="CodeGenEngine"/> assembling the type in creation.</param> /// <param name="evnt">The event to implement.</param> public void Implement(CodeGenEngine engine, GeneratedEvent evnt) { ImplementAccessor(true, evnt, mBackingField); ImplementAccessor(false, evnt, mBackingField); ImplementEventRaiser(evnt, mBackingField); }
/// <summary> /// Reviews the declaration of the property and adds additional type declarations, if necessary. /// </summary> /// <param name="engine">The <see cref="CodeGenEngine"/> assembling the type in creation.</param> /// <param name="property">The property to review.</param> public void Declare(CodeGenEngine engine, GeneratedProperty property) { // add an anonymous field mBackingField = engine.AddField(property.Type, null, property.Kind == PropertyKind.Static, Visibility.Private); }