/// <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");
            }
        }
Example #3
0
 /// <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();
 }
Example #5
0
        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;
        }
Example #6
0
 [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);
     });
 }
Example #7
0
        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);
                }
            }
        }
Example #8
0
        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);
        }
Example #9
0
        /// <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);
            }
        }
Example #10
0
        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);
        }
Example #11
0
        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);
        }
Example #12
0
        /// <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();
        }
Example #13
0
        [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);
        }
Example #14
0
        [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();
        }
Example #19
0
        /// <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();
        }
Example #20
0
        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();
 }
Example #26
0
        /// <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);
            }
        }
Example #27
0
 /// <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);
 }