private Field AddProperty(TypeBuilder builder, FieldStateAllocator fieldStateAllocator, string name, Type type) { var fieldBuilder = builder.DefineField($"_{name}", type, FieldAttributes.Private); var propertyBuilder = builder.DefineProperty(name, PropertyAttributes.None, type, null); var fieldState = fieldStateAllocator.Allocate(); const MethodAttributes propertyMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; var getterBuilder = builder.DefineMethod($"get_{name}", propertyMethodAttributes, type, Type.EmptyTypes); var getterIL = getterBuilder.GetILGenerator(); getterIL.Emit(OpCodes.Ldarg_0); getterIL.Emit(OpCodes.Ldfld, fieldBuilder); getterIL.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getterBuilder); var setterBuilder = builder.DefineMethod($"set_{name}", propertyMethodAttributes, null, new [] { type }); var setterIL = setterBuilder.GetILGenerator(); setterIL.Emit(OpCodes.Ldarg_0); setterIL.Emit(OpCodes.Ldarg_1); setterIL.Emit(OpCodes.Stfld, fieldBuilder); fieldState.MarkAsUsed(setterIL); setterIL.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(setterBuilder); return(new Field(fieldBuilder, propertyBuilder, fieldState)); }
public Type CreateTypeForProperties(IReadOnlyDictionary <string, Type> properties, IReadOnlyCollection <Type> interfaces) { var typeBuilder = _moduleBuilder.DefineUniqueType("ModelProperties"); EnsureKeysAreCaseInsensitiveUnique(properties); foreach (var iface in interfaces) { properties = ImplementPropertiesInterface(typeBuilder, iface, properties); } var fieldStateAllocator = new FieldStateAllocator(typeBuilder); var fieldInfos = new Dictionary <string, Field>(); foreach (var property in properties) { var field = AddProperty(typeBuilder, fieldStateAllocator, property.Key, property.Value); fieldInfos.Add(property.Key, field); } var constructor = typeBuilder.DefineDefaultConstructor(MethodAttributes.Public); typeBuilder.AddInterfaceImplementation(typeof(IProperties <string, object>)); ImplementGetEnumerator(typeBuilder, fieldStateAllocator, fieldInfos); ImplementTryGetValue(typeBuilder, fieldInfos); ImplementSet(typeBuilder, fieldInfos); ImplementCopy(typeBuilder, fieldStateAllocator, constructor, fieldInfos); return(typeBuilder.CreateTypeInfo()); }
private void ImplementGetEnumerator(TypeBuilder typeBuilder, FieldStateAllocator fieldStateAllocator, IReadOnlyDictionary <string, Field> fieldInfos) { var enumeratorTypeGenerator = new ModelPropertyEnumeratorTypeGenerator(_moduleBuilder); // TODO _fieldState var constructor = enumeratorTypeGenerator.CreateEnumeratorType(typeBuilder, fieldStateAllocator.Fields, fieldInfos); MethodBuilder getEnumerator; { var methodBuilder = typeBuilder.DefineMethod( "GetEnumerator", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual, typeof(IEnumerator <KeyValuePair <string, object> >), new Type[0]); var il = methodBuilder.GetILGenerator(); // return new ModelPropertyEnumerator(this, ...fieldState{i}); il.Emit(OpCodes.Ldarg_0); for (var i = 0; i < fieldStateAllocator.Fields.Count; i++) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, fieldStateAllocator.Fields[i]); } il.Emit(OpCodes.Newobj, constructor); il.Emit(OpCodes.Ret); getEnumerator = methodBuilder; } { var methodBuilder = typeBuilder.DefineMethod( "GetEnumerator", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual, typeof(IEnumerator), new Type[0]); var il = methodBuilder.GetILGenerator(); // return this.GetEnumerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, getEnumerator); il.Emit(OpCodes.Ret); } }
private static void ImplementCopy(TypeBuilder typeBuilder, FieldStateAllocator fieldStateAllocator, ConstructorInfo constructor, IReadOnlyDictionary <string, Field> fieldInfos) { var methodBuilder = typeBuilder.DefineMethod( "Copy", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final, typeof(IProperties <string, object>), new Type[0]); var il = methodBuilder.GetILGenerator(); // var clonedProps = new ModelProperties(); il.Emit(OpCodes.Newobj, constructor); var clonedProps = il.DeclareLocal(typeBuilder); il.Emit(OpCodes.Stloc, clonedProps); foreach (var field in fieldStateAllocator.Fields) { // clonedProps._fieldState = this._fieldState il.Emit(OpCodes.Ldloc, clonedProps); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Stfld, field); } foreach (var pair in fieldInfos) { // clonedProps._key = this._key il.Emit(OpCodes.Ldloc, clonedProps); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, pair.Value.Builder); il.Emit(OpCodes.Stfld, pair.Value.Builder); } // return clonedProps; il.Emit(OpCodes.Ldloc, clonedProps); il.Emit(OpCodes.Ret); }