克隆/复制将访问者主体添加到新类型

我正在从现有类型创建动态程序集中的新类型,但只包含选定的属性:

public class EmitTest { public Type Create(Type prototype, Type dynamicBaseType, List includedPropertyList) { AssemblyName aName = new AssemblyName("DynamicAssembly"); AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( aName, AssemblyBuilderAccess.RunAndSave); ModuleBuilder modulBuilder = assemblyBuilder.DefineDynamicModule(aName.Name, aName.Name + ".dll"); string typeName = string.Concat(prototype.Name, "_DynamicType_", Guid.NewGuid().ToString().Replace("-", string.Empty)); TypeBuilder typeBuilder = modulBuilder.DefineType( typeName, TypeAttributes.Public, null, new Type[] { }); foreach (string s in includedPropertyList) { PropertyInfo propertyInfo = prototype.GetProperty(s); if (propertyInfo != null && dynamicBaseType.GetProperty(s) == null) { CreateProperty(typeBuilder, propertyInfo); } } return typeBuilder.CreateType(); } #region Property Creation private void CreateProperty(TypeBuilder typeBuilder, PropertyInfo propertyInfo) { PropertyBuilder propertyBuilder = typeBuilder.DefineProperty( propertyInfo.Name, PropertyAttributes.HasDefault, propertyInfo.PropertyType, null); CreatePropertyBase(typeBuilder, propertyBuilder, propertyInfo); AddAttribute(propertyBuilder, propertyInfo, CreatePropertyAttributeBrowsable); AddAttribute(propertyBuilder, propertyInfo, CreatePropertyAttributeDisplayName); } private void CreatePropertyBase(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo propertyInfo) { FieldBuilder fieldBuilder = typeBuilder.DefineField( string.Concat("m_", propertyInfo.Name), propertyInfo.PropertyType, FieldAttributes.Private); MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; MethodBuilder mbGetAccessor = typeBuilder.DefineMethod( string.Concat("get_", propertyInfo.Name), getSetAttr, propertyInfo.PropertyType, Type.EmptyTypes); ILGenerator mbGetIL = mbGetAccessor.GetILGenerator(); mbGetIL.Emit(OpCodes.Ldarg_0); mbGetIL.Emit(OpCodes.Ldfld, fieldBuilder); mbGetIL.Emit(OpCodes.Ret); MethodBuilder mbSetAccessor = typeBuilder.DefineMethod( string.Concat("set_", propertyInfo.Name), getSetAttr, null, new Type[] { propertyInfo.PropertyType }); ILGenerator mbSetIL = mbSetAccessor.GetILGenerator(); mbSetIL.Emit(OpCodes.Ldarg_0); mbSetIL.Emit(OpCodes.Ldarg_1); mbSetIL.Emit(OpCodes.Stfld, fieldBuilder); mbSetIL.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(mbGetAccessor); propertyBuilder.SetSetMethod(mbSetAccessor); } #endregion Property Creation #region Attribute Createion private void AddAttribute(PropertyBuilder propertyBuilder, PropertyInfo propertyInfo, Action action) where T : Attribute { T attribute = ReflectionHelper.GetAttribute(propertyInfo, typeof(T), false) as T; if (attribute != null) { action(propertyBuilder, attribute); } } private void CreatePropertyAttributeBrowsable(PropertyBuilder propertyBuilder, BrowsableAttribute browsableAttribute) { ConstructorInfo myAttrCtor = typeof(BrowsableAttribute).GetConstructor(new Type[] { typeof(bool) }); CustomAttributeBuilder myAttr = new CustomAttributeBuilder(myAttrCtor, new object[] { browsableAttribute.Browsable }); propertyBuilder.SetCustomAttribute(myAttr); } private void CreatePropertyAttributeDisplayName(PropertyBuilder propertyBuilder, DisplayNameAttribute displayNameAttribute) { ConstructorInfo myAttrCtor2 = typeof(DisplayNameAttribute).GetConstructor(new Type[] { typeof(string) }); CustomAttributeBuilder myAttr2 = new CustomAttributeBuilder(myAttrCtor2, new object[] { displayNameAttribute.DisplayName }); propertyBuilder.SetCustomAttribute(myAttr2); } #endregion Attribute Createion } 

这一切都很好,但在这里我只创建只获取或设置私有字段的简单属性。

我遇到了具有更复杂属性的情况,例如在getter中有类似于“A + B * C”的情况,其中A,B和C是同一类中的属性。

我尝试在CreatePropertyBase方法中创建getter的副本,如下所示:

  MethodBuilder mbNumberGetAccessor = typeBuilder.DefineMethod( string.Concat("get_", propertyInfo.Name), getSetAttr, propertyInfo.PropertyType, Type.EmptyTypes); System.Reflection.MethodInfo mi = propertyInfo.GetGetMethod(); byte[] body = mi.GetMethodBody().GetILAsByteArray(); mbNumberGetAccessor.CreateMethodBody(body, body.Length); 

这显然不起作用。 🙂

我的问题是:是否可以复制具有对同一类中其他属性的引用的get访问器的主体,并且如果可能的话如何执行它。 我正在使用.NET 3.5 SP1

谢谢。

不,您必须从源属性动态反编译IL,因为源属性中的IL将具有对其引用的其他属性的静态PropertyInfo引用。 那些引用将是原始的PropertyInfo而不是你新创建的引用,这可能是它给你错误的原因。

出于好奇,你不仅仅使用匿名类型来做同样的事情是什么原因?

您可以使用此帮助程序( CIL Reader )遍历属性访问器的主体,并通过必要的修改来重构它们