【问题标题】:How can I handle generic method invocations in my DynamicObject?如何在我的 DynamicObject 中处理泛型方法调用?
【发布时间】:2011-10-20 17:02:40
【问题描述】:

我正在尝试构建一个能够处理泛型方法调用的 DynamicObject,但似乎所需的 API(尽管存在于 RC versions of 4.0 Framework 中)已在 RTM 中标记为内部(即 CSharpInvokeMemberBinder 是现在是内部的)。此代码是否有可以在 4.0 RTM 中运行的等效代码?

public class TransparentObject<T> : DynamicObject {
    private readonly T target;

    public TransparentObject(T target) {
        this.target = target;
    }

    public override bool TryInvokeMember(
      InvokeMemberBinder binder, object[] args, out object result) {
        var csBinder = binder as CSharpInvokeMemberBinder;
        var method = typeof(T).GetMethod(binder.Name, BindingFlags.Public
          | BindingFlags.NonPublic | BindingFlags.Instance);
        if (method == null)
            throw new MissingMemberException(string.Format(
              "Method '{0}' not found for type '{1}'", binder.Name, typeof(T)));
        if (csBinder.TypeArguments.Count > 0)
            method = method.MakeGenericMethod(csBinder.TypeArguments.ToArray());
        result = method.Invoke(target, args);
        return true;
    }
}

(代码取自http://bugsquash.blogspot.com/2009/05/testing-private-methods-with-c-40.html

我知道我可以在这里使用反射来获取泛型类型参数,但我正在寻找更好的解决方案 - 如果有的话。

【问题讨论】:

  • 虽然如果您对通过 DLR 在转发方法上推断的泛型感到满意,您可能不需要访问它们,但使用 [ImpromptuInterface]:code.google.com/p/impromptu-interface/wiki/… 它不适用于可以的泛型无法推断,但它会比反射更快。
  • @jbtule 在中等信任度中有效吗?
  • +1 的问题 - 令人愤怒的是,TypeArguments 似乎只能通过内部接口 ICSharpInvokeOrInvokeMemberBinder 访问,对于如何期望您在中等信任中支持动态对象的通用方法有点茫然跨度>
  • @AlexNorcliffe 它应该在中等信任度下工作,但就像我说的那样,它只有在可以通过参数运行时类型推断出泛型参数时才有效,所以这可能是相当有限的。

标签: c# reflection dynamic .net-4.0


【解决方案1】:

我能猜到的最快的等价物:

    private static readonly Func<InvokeMemberBinder, IList<Type>> GetTypeArguments;

    static TransparentObject()
    {
        var type = typeof(RuntimeBinderException).Assembly.GetTypes().Where(x => x.FullName == "Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder").Single();
        var dynamicMethod = new DynamicMethod("@", typeof(IList<Type>), new[] { typeof(InvokeMemberBinder) }, true);
        var il = dynamicMethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Castclass, type);
        il.Emit(OpCodes.Call, type.GetProperty("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments", BindingFlags.Instance | BindingFlags.NonPublic).GetGetMethod(true));
        il.Emit(OpCodes.Ret);
        GetTypeArguments = (Func<InvokeMemberBinder, IList<Type>>)dynamicMethod.CreateDelegate(typeof(Func<InvokeMemberBinder, IList<Type>>));
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        var method = typeof(T).GetMethod(binder.Name, BindingFlags.Public| BindingFlags.NonPublic | BindingFlags.Instance);
        if (method == null) throw new MissingMemberException(string.Format("Method '{0}' not found for type '{1}'", binder.Name, typeof(T)));
        var typeArguments = GetTypeArguments(binder);
        if (typeArguments.Count > 0) method = method.MakeGenericMethod(typeArguments.ToArray());
        result = method.Invoke(target, args);
        return true;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-20
    • 2019-05-20
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 2023-01-20
    • 1970-01-01
    相关资源
    最近更新 更多