private Type Create <T>(BuilderHelper <T> options) where T : class { var type = typeof(T); if (!SinkImplementations.ContainsKey(type)) { this.CreateTypeFor(type, options, SinkImplementations); } return(SinkImplementations[type]); }
private Type GetType <T>() where T : class { var type = typeof(T); if (!type.IsInterface) { throw new ArgumentException("Type is not an Interface"); } var options = new BuilderHelper <T>(this.configuration.DynamicTypePrefix, this.configuration.Namespace); return(this.Create(options)); }
private void CreateTypeFor <T>(Type type, BuilderHelper <T> options, IDictionary <Type, Type> storage) where T : class { const TypeAttributes typeAtts = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Serializable | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit; var typeBuilder = this.moduleBuilder.DefineType( options.TypeName, typeAtts, options.BaseType); typeBuilder.AddInterfaceImplementation(type); typeBuilder.SetCustomAttribute(options.DataContractBuilder); var baseConstructorInfo = options.BaseTypeConstructorInfo; // Default empty constructor var defaultCtorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); var ilDefaultCtorGenerator = defaultCtorBuilder.GetILGenerator(); ilDefaultCtorGenerator.Emit(OpCodes.Ldarg_0); ilDefaultCtorGenerator.Emit(OpCodes.Call, baseConstructorInfo); ilDefaultCtorGenerator.Emit(OpCodes.Nop); ilDefaultCtorGenerator.Emit(OpCodes.Nop); ilDefaultCtorGenerator.Emit(OpCodes.Nop); ilDefaultCtorGenerator.Emit(OpCodes.Ret); // Constructor that takes in the interface type var objCtorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, new[] { type }); var ilObjCtorGenerator = objCtorBuilder.GetILGenerator(); ilObjCtorGenerator.Emit(OpCodes.Ldarg_0); ilObjCtorGenerator.Emit(OpCodes.Call, defaultCtorBuilder); ilObjCtorGenerator.Emit(OpCodes.Nop); ilObjCtorGenerator.Emit(OpCodes.Nop); var compilerGeneratedCtor = typeof(CompilerGeneratedAttribute).GetConstructor(new Type[0]); Debug.Assert(compilerGeneratedCtor != null); var compilerGeneratedAttribute = new CustomAttributeBuilder(compilerGeneratedCtor, new object[0]); var dataMemberCtor = typeof(DataMemberAttribute).GetConstructor(new Type[0]); Debug.Assert(dataMemberCtor != null); const MethodAttributes getSetAtts = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; const MethodAttributes getSetExplicitAtts = getSetAtts | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final; void EmitSet(ILGenerator g, FieldBuilder f) { g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldarg_1); g.Emit(OpCodes.Stfld, f); g.Emit(OpCodes.Ret); } void EmitGet(ILGenerator g, FieldBuilder f) { g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, f); g.Emit(OpCodes.Ret); } MethodBuilder GetGetBuilder(string n, MethodAttributes a, Type t) => typeBuilder.DefineMethod(n, a, t, Type.EmptyTypes); MethodBuilder GetSetBuilder(string n, MethodAttributes a, Type t) => typeBuilder.DefineMethod(n, a, typeof(void), new[] { t }); FieldBuilder GetBackingField(string n, Type a) => typeBuilder.DefineField("<" + n + ">k__BackingField", a, FieldAttributes.Private); var methods = new List <MethodInfo>(type.GetAll(x => x.GetMethods())); var properties = new List <PropertyInfo>(type.GetAll(x => x.GetProperties())); foreach (var pi in properties) { var piName = pi.Name; var propertyType = pi.PropertyType; var hasSet = false; var hasGet = false; var propertyBuilder = typeBuilder.DefineProperty( piName, PropertyAttributes.HasDefault, CallingConventions.HasThis, propertyType, null); var field = GetBackingField(piName, propertyType); field.SetCustomAttribute(compilerGeneratedAttribute); var getMethod = pi.GetGetMethod(); if (getMethod != null) { hasGet = true; var getBuilder = GetGetBuilder(getMethod.Name, getSetAtts, propertyType); EmitGet(getBuilder.GetILGenerator(), field); propertyBuilder.SetGetMethod(getBuilder); var getExplicitBuilder = GetGetBuilder( type.Name + "." + getMethod.Name, getSetExplicitAtts, propertyType); EmitGet(getExplicitBuilder.GetILGenerator(), field); typeBuilder.DefineMethodOverride(getExplicitBuilder, getMethod); } var setMethod = pi.GetSetMethod(); string setMethodName; if (setMethod != null) { hasSet = true; setMethodName = setMethod.Name; } else { // Must have a get method otherwise it wouldn't be a property. setMethodName = pi.GetGetMethod().Name.Replace("set_", "get_"); } var setBuilder = GetSetBuilder(setMethodName, getSetAtts, propertyType); EmitSet(setBuilder.GetILGenerator(), field); propertyBuilder.SetSetMethod(setBuilder); // Keep to the interface contract, only add a set to the interface implementation if (hasSet) { var setExplicitBuilder = GetSetBuilder( type.Name + "." + setMethod.Name, getSetExplicitAtts, propertyType); EmitSet(setExplicitBuilder.GetILGenerator(), field); typeBuilder.DefineMethodOverride(setExplicitBuilder, setMethod); } if (hasGet) { // property for serialization, apply the DataMember attribute // to the property. propertyBuilder.SetCustomAttribute( new CustomAttributeBuilder(dataMemberCtor, new object[0])); // Emit property set in the ctor that takes an instance of the // interface that this type supports. ilObjCtorGenerator.Emit(OpCodes.Nop); ilObjCtorGenerator.Emit(OpCodes.Ldarg_0); ilObjCtorGenerator.Emit(OpCodes.Ldarg_1); ilObjCtorGenerator.Emit(OpCodes.Callvirt, pi.GetGetMethod()); ilObjCtorGenerator.Emit(OpCodes.Call, propertyBuilder.GetSetMethod()); } if (hasGet) { methods.Remove(getMethod); } if (hasSet) { methods.Remove(setMethod); } } // Complete the ctor that takes the interface type as an argument. ilObjCtorGenerator.Emit(OpCodes.Nop); ilObjCtorGenerator.Emit(OpCodes.Nop); ilObjCtorGenerator.Emit(OpCodes.Ret); // Methods are no-ops; if there is a // return value, return a default value or null foreach (var methodInfo in methods) { var returnType = methodInfo.ReturnType; var methodBuilder = typeBuilder.DefineMethod( methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, returnType, methodInfo.GetParameters().Select(parameterInfo => parameterInfo.ParameterType).ToArray()); ilDefaultCtorGenerator = methodBuilder.GetILGenerator(); if (returnType != typeof(void)) { var localBuilder = ilDefaultCtorGenerator.DeclareLocal(returnType); ilDefaultCtorGenerator.Emit(OpCodes.Ldloc, localBuilder); } ilDefaultCtorGenerator.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, methodInfo); } // Define override ToString() for diagnostic purposes var sB = typeBuilder.DefineMethod( "ToString", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(string), Type.EmptyTypes); var sG = sB.GetILGenerator(); sG.Emit(OpCodes.Nop); // ReSharper disable AssignNullToNotNullAttribute sG.Emit(OpCodes.Newobj, typeof(System.Text.StringBuilder).GetConstructor(Type.EmptyTypes)); // ReSharper restore AssignNullToNotNullAttribute // Ldloc_0 sG.Emit(OpCodes.Stloc_0, sG.DeclareLocal(typeof(System.Text.StringBuilder))); sG.Emit(OpCodes.Ldloc_0); sG.Emit(OpCodes.Ldstr, options.TypeName + " : " + type.FullName + " {"); sG.Emit(OpCodes.Callvirt, typeof(System.Text.StringBuilder).GetMethod("AppendLine", new[] { typeof(string) })); sG.Emit(OpCodes.Pop); foreach (var p in from p in new List <PropertyInfo>(type.GetAll(x => x.GetProperties())) let getM = p.GetGetMethod() where getM != null where !getM.ReturnType.IsClass && !getM.ReturnType.IsInterface select p) { sG.Emit(OpCodes.Ldloc_0); if (p.PropertyType == typeof(byte)) { sG.Emit(OpCodes.Ldstr, " " + p.Name + ": 0x{0:x2}\n"); } else { sG.Emit(OpCodes.Ldstr, " " + p.Name + ": {0}\n"); } sG.Emit(OpCodes.Ldarg_0); sG.Emit(OpCodes.Call, p.GetGetMethod()); sG.Emit(OpCodes.Box, p.PropertyType); sG.Emit(OpCodes.Callvirt, typeof(System.Text.StringBuilder).GetMethod("AppendFormat", new[] { typeof(string), typeof(object) })); sG.Emit(OpCodes.Pop); } sG.Emit(OpCodes.Ldloc_0); sG.Emit(OpCodes.Ldstr, "} // " + options.TypeName); sG.Emit(OpCodes.Callvirt, typeof(System.Text.StringBuilder).GetMethod("AppendLine", new[] { typeof(string) })); sG.Emit(OpCodes.Pop); sG.Emit(OpCodes.Ldloc_0); sG.Emit(OpCodes.Callvirt, typeof(System.Text.StringBuilder).GetMethod("ToString", Type.EmptyTypes)); sG.Emit(OpCodes.Ret); var createdType = typeBuilder.CreateType(); storage[type] = createdType; }