Как я могу обработать вызовы универсального метода в моем DynamicObject? - PullRequest
5 голосов
/ 05 августа 2011

Я пытаюсь создать DynamicObject, который может обрабатывать вызовы универсальных методов, но кажется, что необходимый API - хотя и присутствует в RC-версиях 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)

Мне известно, что я могу использовать рефлексию для получения здесь параметров универсального типа, но я ищу более подходящее решение - если оно есть.

1 Ответ

0 голосов
/ 08 августа 2011

Самый быстрый эквивалент, который я могу догадаться:

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