2010-07-30 1 views
3

Я создаю новый тип в динамической сборки от существующего типа, но только с выбранными свойствами включать:Клонирование/копирование получить аксессора тело нового типа

public class EmitTest 
{ 
    public Type Create(Type prototype, Type dynamicBaseType, List<string> 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<BrowsableAttribute>(propertyBuilder, propertyInfo, CreatePropertyAttributeBrowsable); 
     AddAttribute<DisplayNameAttribute>(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<T>(PropertyBuilder propertyBuilder, PropertyInfo propertyInfo, Action<PropertyBuilder, T> 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 так:

 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 accessor, имеющее ссылки на другие свойства в том же классе, и, если возможно, как это сделать. Я использую .NET 3.5 SP1

Спасибо.

ответ

0

Нет, вам придется динамически декомпилировать IL из исходного свойства, потому что IL в исходном свойстве будет иметь статические ссылки PropertyInfo на другие свойства, на которые он ссылается. И эти ссылки будут относиться к исходной PropertyInfo, а не к вашим вновь созданным, что, вероятно, стало причиной того, что это дало вам ошибки.

Из любопытства, по какой причине вы не просто используете анонимный тип, чтобы делать то же самое?

+0

я должен работать с литералами, массив строк, содержащих имена свойств, и я должен добавить атрибуты для тех, свойства и т. д. Я не вижу, как я могу использовать анонимные типы со всем этим, или я могу? :) –

0

Вы можете использовать этот хелпер (CIL Reader) для обхода тела аксессоров собственности и восстановить их с необходимыми изменениями

 Смежные вопросы

  • Нет связанных вопросов^_^