gpt4 book ai didi

c# - 克隆/复制获取访问器主体到新类型

转载 作者:行者123 更新时间:2023-11-30 18:44:06 30 4
gpt4 key购买 nike

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

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
}

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

我遇到过我有更复杂属性的情况,例如在 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 的引用,而不是对您新创建的 PropertyInfo 的引用,这可能就是它给您错误的原因。

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

关于c# - 克隆/复制获取访问器主体到新类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3372319/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com