/// <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 #2
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();
        }
        /// <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");
            }
        }
Example #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ClassDefinition"/> class.
        /// </summary>
        /// <param name="baseClass">Base class to derive the created class from.</param>
        /// <param name="generatePassThroughConstructors">
        /// true to generate pass-through constructors;
        /// false to generate a parameterless constructor only.
        /// </param>
        /// <param name="name">Name of the class to create (null to keep the name of the base class).</param>
        public ClassDefinition(Type baseClass, bool generatePassThroughConstructors, string name = null)
        {
            if (baseClass == null)
            {
                throw new ArgumentNullException(nameof(baseClass));
            }

            // ensure that the base class is really a class
            if (!baseClass.IsClass)
            {
                string error = string.Format("The specified type ({0}) for the base class is not a class.", baseClass.FullName);
                throw new ArgumentException(error);
            }

            CodeGenHelpers.CheckTypeIsTotallyPublic(baseClass);

            mTypeName      = name;
            mBaseClassType = baseClass;
            mGeneratePassThroughConstructors = generatePassThroughConstructors;
        }
        /// <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>
        /// Adds the event raiser method.
        /// </summary>
        /// <param name="evnt">Event to implement.</param>
        /// <param name="backingField">Multicast delegate field backing the event.</param>
        private static void ImplementEventRaiser(GeneratedEvent evnt, IGeneratedField backingField)
        {
            ILGenerator msil = evnt.Raiser.MethodBuilder.GetILGenerator();

            if (evnt.Type == typeof(EventHandler) || evnt.Type == typeof(EventHandler <EventArgs>))
            {
                // System.EventHandler
                // System.EventHandler<EventArgs>

                FieldInfo    EventArgsEmpty      = typeof(EventArgs).GetField("Empty");
                LocalBuilder handlerLocalBuilder = msil.DeclareLocal(backingField.FieldBuilder.FieldType);
                Label        label = msil.DefineLabel();
                if (evnt.Kind == EventKind.Static)
                {
                    msil.Emit(OpCodes.Ldsfld, backingField.FieldBuilder);
                    msil.Emit(OpCodes.Stloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Brfalse_S, label);
                    msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Ldnull);                      // load sender (null)
                    msil.Emit(OpCodes.Ldsfld, EventArgsEmpty);      // load event arguments
                }
                else
                {
                    msil.Emit(OpCodes.Ldarg_0);
                    msil.Emit(OpCodes.Ldfld, backingField.FieldBuilder);
                    msil.Emit(OpCodes.Stloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Brfalse_S, label);
                    msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Ldarg_0);                     // load sender (this)
                    msil.Emit(OpCodes.Ldsfld, EventArgsEmpty);      // load event arguments
                }

                MethodInfo invokeMethod = backingField.FieldBuilder.FieldType.GetMethod("Invoke");
                msil.Emit(OpCodes.Callvirt, invokeMethod);
                msil.MarkLabel(label);
                msil.Emit(OpCodes.Ret);

                return;
            }
            else if (evnt.Type.IsGenericType && evnt.Type.GetGenericTypeDefinition() == typeof(EventHandler <>))
            {
                // EventHandler<T> with T derived from System.EventArgs

                LocalBuilder handlerLocalBuilder = msil.DeclareLocal(backingField.FieldBuilder.FieldType);
                Label        label = msil.DefineLabel();
                if (evnt.Kind == EventKind.Static)
                {
                    msil.Emit(OpCodes.Ldsfld, backingField.FieldBuilder);
                    msil.Emit(OpCodes.Stloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Brfalse_S, label);
                    msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Ldnull);                      // load sender (null)
                    msil.Emit(OpCodes.Ldarg_0);                     // load event arguments
                }
                else
                {
                    msil.Emit(OpCodes.Ldarg_0);
                    msil.Emit(OpCodes.Ldfld, backingField.FieldBuilder);
                    msil.Emit(OpCodes.Stloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Brfalse_S, label);
                    msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                    msil.Emit(OpCodes.Ldarg_0);                     // load sender (this)
                    msil.Emit(OpCodes.Ldarg_1);                     // load event arguments
                }

                MethodInfo invokeMethod = backingField.FieldBuilder.FieldType.GetMethod("Invoke");
                msil.Emit(OpCodes.Callvirt, invokeMethod);
                msil.MarkLabel(label);
                msil.Emit(OpCodes.Ret);

                return;
            }
            else if (typeof(Delegate).IsAssignableFrom(evnt.Type))
            {
                MethodInfo   invokeMethod        = backingField.FieldBuilder.FieldType.GetMethod("Invoke");
                LocalBuilder handlerLocalBuilder = msil.DeclareLocal(backingField.FieldBuilder.FieldType);
                Label        label = msil.DefineLabel();

                if (evnt.Kind == EventKind.Static)
                {
                    msil.Emit(OpCodes.Ldsfld, backingField.FieldBuilder);
                }
                else
                {
                    msil.Emit(OpCodes.Ldarg_0);
                    msil.Emit(OpCodes.Ldfld, backingField.FieldBuilder);
                }

                msil.Emit(OpCodes.Stloc, handlerLocalBuilder);
                msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                msil.Emit(OpCodes.Brfalse_S, label);
                msil.Emit(OpCodes.Ldloc, handlerLocalBuilder);
                int argumentOffset = evnt.Kind == EventKind.Static ? 0 : 1;
                for (int i = 0; i < evnt.Raiser.ParameterTypes.Length; i++)
                {
                    CodeGenHelpers.EmitLoadArgument(msil, argumentOffset + i);
                }
                msil.Emit(OpCodes.Callvirt, invokeMethod);
                msil.MarkLabel(label);
                msil.Emit(OpCodes.Ret);
                return;
            }

            throw new NotSupportedException("The event type is not supported.");
        }
Example #7
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);
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="GeneratedProperty"/> class
        /// (associates a standard <see cref="System.Windows.PropertyMetadata"/> object with a default value with the dependency property).
        /// </summary>
        /// <param name="engine">The code generation engine.</param>
        /// <param name="name">Name of the property (may be null).</param>
        /// <param name="type">Type of the property.</param>
        /// <param name="isReadOnly">
        /// true, if the dependency property is read-only;
        /// false, if it is read-write.
        /// </param>
        /// <param name="initializer">A method that provides code creating the default value of the dependency property (may be null to use the type's default value).</param>
        internal GeneratedDependencyProperty(
            CodeGenEngine engine,
            string name,
            Type type,
            bool isReadOnly,
            DependencyPropertyInitializer initializer = null) :
            base(engine)
        {
            mName       = name;
            mIsReadOnly = isReadOnly;

            // add the dependency property
            if (mIsReadOnly)
            {
                mDependencyPropertyField = (IGeneratedFieldInternal)engine.AddStaticField <System.Windows.DependencyPropertyKey>(
                    name + "Property",
                    Visibility.Public,
                    (msil, field) =>
                {
                    MethodInfo registerReadOnlyMethod = typeof(System.Windows.DependencyProperty).GetMethod(
                        "RegisterReadOnly",
                        BindingFlags.Static,
                        null,
                        new Type[] { typeof(string), typeof(Type), typeof(Type), typeof(System.Windows.PropertyMetadata) },
                        null);

                    msil.Emit(OpCodes.Ldstr, mName);
                    msil.Emit(OpCodes.Ldtoken, type);
                    msil.Emit(OpCodes.Ldtoken, engine.TypeBuilder);

                    // create PropertyMetadata object
                    ConstructorInfo propertyMetadataConstructor = typeof(System.Windows.PropertyMetadata).GetConstructor(new Type[] { typeof(object) });
                    if (initializer != null)
                    {
                        initializer(msil, this);
                    }
                    else
                    {
                        CodeGenHelpers.EmitLoadDefaultValue(msil, type, true);
                    }
                    msil.Emit(OpCodes.Newobj, propertyMetadataConstructor);

                    // call DependencyProperty.RegisterReadOnly() method
                    msil.Emit(OpCodes.Call, registerReadOnlyMethod);
                });
            }
            else
            {
                mDependencyPropertyField = (IGeneratedFieldInternal)engine.AddStaticField <System.Windows.DependencyProperty>(
                    name + "Property",
                    Visibility.Public,
                    (msil, field) =>
                {
                    MethodInfo registerMethod = typeof(System.Windows.DependencyProperty).GetMethod(
                        "Register",
                        BindingFlags.Public | BindingFlags.Static,
                        null,
                        new Type[] { typeof(string), typeof(Type), typeof(Type), typeof(System.Windows.PropertyMetadata) },
                        null);

                    msil.Emit(OpCodes.Ldstr, mName);
                    msil.Emit(OpCodes.Ldtoken, type);
                    msil.Emit(OpCodes.Ldtoken, engine.TypeBuilder);

                    // create PropertyMetadata object
                    ConstructorInfo propertyMetadataConstructor = typeof(System.Windows.PropertyMetadata).GetConstructor(new Type[] { typeof(object) });
                    if (initializer != null)
                    {
                        initializer(msil, this);
                    }
                    else
                    {
                        CodeGenHelpers.EmitLoadDefaultValue(msil, type, true);
                    }
                    msil.Emit(OpCodes.Newobj, propertyMetadataConstructor);

                    // call DependencyProperty.Register() method
                    msil.Emit(OpCodes.Call, registerMethod);
                });
            }

            // add the accessor property
            mImplementation   = new PropertyImplementation_DependencyProperty(this);
            mAccessorProperty = engine.AddProperty(
                name,
                type,
                PropertyKind.Normal,
                mImplementation);

            mAccessorProperty.GetAccessor.Visibility = CodeGeneration.Visibility.Public;
            mAccessorProperty.SetAccessor.Visibility = CodeGeneration.Visibility.Internal;
        }