使用 Reflection.Emit 覆盖属性定义
我正在尝试使用 Reflection.Emit (TypeBuilder) 来实现此模式:
public class ClassToBeProxied
{
public virtual object Property1 { get; set; }
}
public class Proxy : ClassToBeProxied
{
[AttributeToBeAdded]
public override object Property1
{
get
{
//do something else to return the object - i.e get it from the database
return null; //stub
}
set
{
//do something else to set the object - i.e, save it to a database
}
}
}
如果我所做的只是拦截 get 和 set 方法,那么这是可行的:
PropertyInfo info = typeof(ClassToBeProxied).GetProperty("Property1", BindingFlags.Public | BindingFlags.Instance);
{
MethodBuilder pGet = typeBuilder.DefineMethod("get_" + info.Name, MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, info.PropertyType, Type.EmptyTypes);
ILGenerator pILGet = pGet.GetILGenerator();
//The proxy object
pILGet.Emit(OpCodes.Ldarg_0);
//The database
pILGet.Emit(OpCodes.Ldfld, database);
//The proxy object
pILGet.Emit(OpCodes.Ldarg_0);
//The ObjectId to look for
pILGet.Emit(OpCodes.Ldfld, f);
pILGet.Emit(OpCodes.Callvirt, typeof(MongoDatabase).GetMethod("Find", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ObjectId) }, null).MakeGenericMethod(info.PropertyType));
pILGet.Emit(OpCodes.Ret);
MethodBuilder pSet = typeBuilder.DefineMethod("set_" + info.Name, MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new Type[] { info.PropertyType });
ILGenerator pILSet = pSet.GetILGenerator();
pILSet.Emit(OpCodes.Ldarg_0);
pILSet.Emit(OpCodes.Ldarg_1);
pILSet.Emit(OpCodes.Ldarg_0);
pILSet.Emit(OpCodes.Ldfld, database);
pILSet.Emit(OpCodes.Call, typeof(ProxyBuilder).GetMethod("SetValueHelper", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object), typeof(MongoDatabase) }, null));
pILSet.Emit(OpCodes.Stfld, f);
pILSet.Emit(OpCodes.Ret);
//Edit: Added fix
newProp.SetSetMethod(pSet);
newProp.SetGetMethod(pGet);
}
但我需要做的是向 Property 添加一个属性。我不知道该怎么做。
如果我添加一个新的 PropertyDefinition:,
PropertyBuilder newProp = typeBuilder.DefineProperty(info.Name, PropertyAttributes.None, info.PropertyType, Type.EmptyTypes);
newProp.SetCustomAttribute(new CustomAttributeBuilder(typeof(AttributeToBeAdded).GetConstructor(Type.EmptyTypes), Type.EmptyTypes, new FieldInfo[0], new object[0]));
然后对生成的类型调用 GetProperties(),则会出现两个同名的属性。但是,如果我手动构建代码(如上例所示),并调用 typeof(Proxy).GetProperties(),则只有一个 Property(派生类属性)可见。这是我需要的行为,但我似乎无法通过 Reflection.Emit 到达那里,
如果我需要添加更多信息以使问题更清晰,请告诉我。
I'm trying to implement this pattern using Reflection.Emit (TypeBuilder):
public class ClassToBeProxied
{
public virtual object Property1 { get; set; }
}
public class Proxy : ClassToBeProxied
{
[AttributeToBeAdded]
public override object Property1
{
get
{
//do something else to return the object - i.e get it from the database
return null; //stub
}
set
{
//do something else to set the object - i.e, save it to a database
}
}
}
If all I were doing was intercepting the get and set methods, then this works:
PropertyInfo info = typeof(ClassToBeProxied).GetProperty("Property1", BindingFlags.Public | BindingFlags.Instance);
{
MethodBuilder pGet = typeBuilder.DefineMethod("get_" + info.Name, MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, info.PropertyType, Type.EmptyTypes);
ILGenerator pILGet = pGet.GetILGenerator();
//The proxy object
pILGet.Emit(OpCodes.Ldarg_0);
//The database
pILGet.Emit(OpCodes.Ldfld, database);
//The proxy object
pILGet.Emit(OpCodes.Ldarg_0);
//The ObjectId to look for
pILGet.Emit(OpCodes.Ldfld, f);
pILGet.Emit(OpCodes.Callvirt, typeof(MongoDatabase).GetMethod("Find", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ObjectId) }, null).MakeGenericMethod(info.PropertyType));
pILGet.Emit(OpCodes.Ret);
MethodBuilder pSet = typeBuilder.DefineMethod("set_" + info.Name, MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new Type[] { info.PropertyType });
ILGenerator pILSet = pSet.GetILGenerator();
pILSet.Emit(OpCodes.Ldarg_0);
pILSet.Emit(OpCodes.Ldarg_1);
pILSet.Emit(OpCodes.Ldarg_0);
pILSet.Emit(OpCodes.Ldfld, database);
pILSet.Emit(OpCodes.Call, typeof(ProxyBuilder).GetMethod("SetValueHelper", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object), typeof(MongoDatabase) }, null));
pILSet.Emit(OpCodes.Stfld, f);
pILSet.Emit(OpCodes.Ret);
//Edit: Added fix
newProp.SetSetMethod(pSet);
newProp.SetGetMethod(pGet);
}
But what I need to do is also add an attribute to the Property. I can't figure out how to do this.
If I add a new PropertyDefinition:
PropertyBuilder newProp = typeBuilder.DefineProperty(info.Name, PropertyAttributes.None, info.PropertyType, Type.EmptyTypes);
newProp.SetCustomAttribute(new CustomAttributeBuilder(typeof(AttributeToBeAdded).GetConstructor(Type.EmptyTypes), Type.EmptyTypes, new FieldInfo[0], new object[0]));
and then call GetProperties() on the generated type, two properties with the same name appear. However, if I build the code by hand (as in the example above), and call typeof(Proxy).GetProperties(), only one Property (the derived class property) is visible. This is the behavior I need, but I can't seem to get there with Reflection.Emit
Please let me know if I need to add more info to make the question clearer.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
所以答案是添加这个:
查看编辑后的问题。
答案有点矛盾 http://www.gutgames.com/ post/Overridding-a-Property-With-ReflectionEmit/
但它似乎有效。
So the answer was add this:
See the edited question.
The answer kind of contradicts http://www.gutgames.com/post/Overridding-a-Property-With-ReflectionEmit/
but it seems to work.