C# .NET创建结构属性getter委托
我有一个创建属性getter委托的方法:C# .NET创建结构属性getter委托,c#,C#,我有一个创建属性getter委托的方法: private static Delegate CreatePropertyGetter(PropertyInfo propertyInfo) { MethodInfo propertyGetter = propertyInfo.GetGetMethod(); DynamicMethod dynGetter = new DynamicMethod
private static Delegate CreatePropertyGetter(PropertyInfo propertyInfo)
{
MethodInfo propertyGetter = propertyInfo.GetGetMethod();
DynamicMethod dynGetter = new DynamicMethod
(
String.Concat("DM$MEMBER_GETTER_", propertyInfo.Name),
propertyInfo.PropertyType,
new Type[1] { propertyInfo.DeclaringType },
propertyInfo.DeclaringType,
true
);
ILGenerator ilGen = dynGetter.GetILGenerator();
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.EmitCall(propertyInfo.DeclaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, propertyGetter, null);
ilGen.Emit(OpCodes.Ret);
return dynGetter.CreateDelegate(typeof(MemberGetter<,>).MakeGenericType(propertyInfo.DeclaringType, propertyInfo.PropertyType));
}
私有静态委托CreatePropertyGetter(PropertyInfo PropertyInfo)
{
MethodInfo propertyGetter=propertyInfo.GetGetMethod();
DynamicMethod dynGetter=新的DynamicMethod
(
String.Concat(“DM$MEMBER\u GETTER”,propertyInfo.Name),
propertyInfo.PropertyType,
新类型[1]{propertyInfo.DeclaringType},
属性INFO.DeclaringType,
真的
);
ILGenerator ilGen=dynGetter.GetILGenerator();
ilGen.Emit(操作码Ldarg_0);
ilGen.EmitCall(propertyInfo.DeclaringType.IsValueType?操作码。调用:操作码。Callvirt,propertyGetter,null);
ilGen.Emit(操作码Ret);
返回dynGetter.CreateDelegate(typeof(MemberGetter).MakeGenericType(propertyInfo.DeclaringType,propertyInfo.PropertyType));
}
这段代码可以很好地处理类,但是当我尝试获取属性值时,结构会抛出ArgumentNullException。当您必须在IL计算堆栈上提供指向该结构的托管指针时。现在您正在加载结构本身,这是不正确的
你得把这个扔掉。最好使用
Delegate.CreateDelegate
获取getter方法的委托。尝试从以下内容更改一行:
ilGen.Emit(OpCodes.Ldarg_0);
为此:
ilGen.Emit(propertyInfo.DeclaringType.IsValueType ? OpCodes.Ldarga : OpCodes.Ldarg, 0);
这将加载第一个参数(位于堆栈上)的地址,这是在结构上调用实例方法所必需的。但是,我更喜欢使用System.Linq.Expressions而不是Emit。关于这一点,我不太清楚。您正在生成一个通用委托,但只是返回委托。您会使用DynamicVoke调用它,还是应该如何工作?如果你可以施放它,那么你已经知道类型信息,所以像这样的动态效果似乎大大降低。此外,您似乎没有取消绑定返回值。如果这是一个值类型,它将导致问题。如果是我,我会更像这样做
public static PropValDelegate CreatePropertyGetter<TIn>(PropertyInfo propertyInfo, TIn ownerObj)
{
MethodInfo propertyGetter = propertyInfo.GetGetMethod();
DynamicMethod dynGetter = new DynamicMethod
(
String.Empty, typeof(object), new Type[1] {typeof(TIn)},
propertyInfo.DeclaringType, true
);
ILGenerator ilGen = dynGetter.GetILGenerator();
ilGen.Emit(propertyInfo.DeclaringType.IsValueType ? OpCodes.Ldarga : OpCodes.Ldarg, 0);
ilGen.EmitCall(propertyInfo.DeclaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, propertyGetter, null);
if (propertyInfo.PropertyType.IsValueType)
{
ilGen.Emit(OpCodes.Box, propertyInfo.PropertyType);
}
ilGen.Emit(OpCodes.Ret);
return (lambdaObject) => (PropValDelegate<TIn>)dynGetter.CreateDelegate(typeof(PropValDelegate<TIn>));
}
公共静态PropValDelegate CreatePropertyGetter(PropertyInfo PropertyInfo,TIn ownerObj)
{
MethodInfo propertyGetter=propertyInfo.GetGetMethod();
DynamicMethod dynGetter=新的DynamicMethod
(
String.Empty,typeof(object),新类型[1]{typeof(TIn)},
propertyInfo.DeclaringType,true
);
ILGenerator ilGen=dynGetter.GetILGenerator();
ilGen.Emit(propertyInfo.DeclaringType.IsValueType?opcode.Ldarga:opcode.Ldarg,0);
ilGen.EmitCall(propertyInfo.DeclaringType.IsValueType?操作码。调用:操作码。Callvirt,propertyGetter,null);
if(propertyInfo.PropertyType.IsValueType)
{
Emit(opcode.Box,propertyInfo.PropertyType);
}
ilGen.Emit(操作码Ret);
return(lambdaObject)=>(PropValDelegate)dynGetter.CreateDelegate(typeof(PropValDelegate));
}
我们有一个泛型和非泛型版本的委托,但每个委托都接受一个对象输入,这样我们就可以使用泛型的敏捷性更轻松地进行早期绑定调用和缓存为什么不直接调用,而不用IL?此外,它会更快。是否存在内部异常?MemberGetter的定义是什么?你用它代替Func有什么原因吗?如何调用创建的委托?您正在传递实例吗?Lucas,请给出上面代码更快的示例。@KozilovMichael:第一行,然后
返回CreateDelegate(typeof(MemberGetter)。MakeGenericType(propertyInfo.DeclaringType,propertyInfo.PropertyType),propertyGetter)
或摆脱MemberGetter
并使用.NET为您提供的Func
或Converter
。