.NET创建struct属性getter委托

时间:2015-03-20 21:31:03

标签: c#

我有创建属性getter委托的方法:

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));
    }

这段代码适用于类,但是当我尝试获取属性值时,结构会抛出ArgumentNullException。

3 个答案:

答案 0 :(得分:0)

calling a method on a struct时,您必须在IL评估堆栈上提供指向该结构的托管指针。现在你正在加载不正确的结构本身。

你需要扔掉它。最好使用Delegate.CreateDelegate来获取getter方法的委托。

答案 1 :(得分:0)

尝试更改此行:

ilGen.Emit(OpCodes.Ldarg_0);

到此:

ilGen.Emit(propertyInfo.DeclaringType.IsValueType ? OpCodes.Ldarga : OpCodes.Ldarg, 0);

这会加载第一个参数(位于堆栈上)的地址,这是在结构上调用实例方法所必需的 但是,我更喜欢使用System.Linq.Expressions而不是Emit。

答案 2 :(得分:0)

我不清楚这方面的一些事情。您正在创建一个通用委托,但之后只返回Delegate。你会使用DynamicInvoke调用它吗?或者它应该如何工作?如果你可以投射它然后你已经知道类型信息所以这样的动态的功效似乎大大减少。此外,您似乎没有取消装箱返回值。如果这是一种价值类型,它会导致问题。如果是我,我会更喜欢这样做

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>));
    }

我们有一个通用的非泛型版本的委托,但每个都接受一个对象输入,所以我们可以通过泛型的竖琴更容易地进行早期绑定调用和缓存