/// <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="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"); } }
/// <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."); }
/// <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; }