【问题标题】:How to Build Expression Tree for Invoke Method from Generic Interface如何从通用接口为调用方法构建表达式树
【发布时间】:2021-11-29 07:56:54
【问题描述】:

我很抱歉地问,我怎样才能使用其他那个 method.Invoke 来调用方法,因为有些文章说,method.Invoke 的性能较慢。 实际上我使用的是 .NET Core 3.1。

例如,我有一个类似这样的结构代码。

public class Message { }

    public class MyMessageType : Message { }

    public class MyMessageResult
    {
        public bool Status { get; set; }
        public DateTime Date => DateTime.Now;
    }

public interface IEncapsulatedMessageHandlerV2<T, TResult> where T : class
    {
        Task<TResult> HandleMessageResultAsync(T message);
    }

    public abstract class EncasulatedMessageHandlerV2<T, TResult> : IEncapsulatedMessageHandlerV2<T, TResult> where T : Message
    {
        public abstract Task<TResult> HandleMessageResultExecAsync(T message);

        async Task<TResult> IEncapsulatedMessageHandlerV2<T, TResult>.HandleMessageResultAsync(T message)
        {
            var msg = message as T;
            if (msg != null)
                return await HandleMessageResultExecAsync(msg);
            return default;
        }
    }

    public class HandlerV2 : EncasulatedMessageHandlerV2<MyMessageType, MyMessageResult>
    {
        public override Task<MyMessageResult> HandleMessageResultExecAsync(MyMessageType message)
        {
            Console.WriteLine("Yo Async!");
            return Task.FromResult(new MyMessageResult
            {
                Status = true
            });
        }
    }

我可以使用method.Invoke成功调用

static TResponse UsingMethodInvoke<TResponse>()
        {
            // Assume, i was build this using MakeGenericMethod
            var type = typeof(IEncapsulatedMessageHandlerV2<MyMessageType, MyMessageResult>);

            var typeActivator = typeof(HandlerV2);
            var instance = Activator.CreateInstance(typeActivator);

            var method = type.GetMethod("HandleMessageResultAsync");
            var tsk = (Task<TResponse>)method.Invoke(instance, new[] { new MyMessageType() });
            var result = tsk.GetAwaiter().GetResult();
            return result;
        }

我也尝试使用Dynamic,不幸的是他们不能通过抽象HandleMessageResultAsync调用,而只能通过实现类HandleMessageResultExecAsync

static TResponse UsingDynamicInvoke<TResponse>()
        {
            // Assume, i was build this using MakeGenericMethod
            var typeActivator = typeof(HandlerV2);
            var instance = Activator.CreateInstance(typeActivator);

            var tsk = (Task<TResponse>)((dynamic)instance).HandleMessageResultExecAsync(new MyMessageType());
            var result = tsk.GetAwaiter().GetResult();
            return result;
        }

我被 stackoverflow Speeding up Reflection Invoke C#/.NET 跟踪,我被卡住了

static void ActivatorMyMessageResultAsnc()
        {
            var type = typeof(HandlerV2);
            var instance = Activator.CreateInstance(type);
            var method = type.GetMethod("HandleMessageResultAsync", BindingFlags.Instance | BindingFlags.Public);

            var originalType = type;
            // Loop until we hit the type we want.
            while (!(type.IsGenericType) || type.GetGenericTypeDefinition() != typeof(EncasulatedMessageHandlerV2<,>))
            {
                type = type.BaseType;
                if (type == null)
                    throw new ArgumentOutOfRangeException("type");
            }

            var messageType = type.GetGenericArguments()[0]; // MyMessageType

            // Use expression to create a method we can.
            var instExpr = Expression.Parameter(typeof(object), "instance");
            var paramExpr = Expression.Parameter(typeof(Message), "message");
            // (Handler)instance;
            var instCastExpr = Expression.Convert(instExpr, originalType);
            // (MyMessageType)message
            var castExpr = Expression.Convert(paramExpr, messageType);
            // ((Handler)inst).HandleMessage((MyMessageType)message)
            var invokeExpr = Expression.Call(instCastExpr, method, castExpr); // <--- this give me error

// i'm stuck, i don't know what should i do next

            ////// Assume this is build from MakeGeneric too
            ////var delType = typeof(Func<object, Message, Task<MessageResult>>);

            //var lambda = Expression.Lambda<Func<object, Message, Task<object>>>(invokeExpr, instExpr, paramExpr);
            //var compiled = lambda.Compile();
            //Func<Message, Task<object>> hook = x => compiled(instance, x);

或者,有没有其他方法可以通过动态方式调用方法,这比方法更快。调用

提前致谢,

PS:对不起我的英语不好

【问题讨论】:

  • 你可以通过稍微改变你的设计来避免这一切。只需引入 IEncapsulatedMessageHandlerV2 扩展的非泛型接口。

标签: c# methods expression-trees invoke method-call


【解决方案1】:

我有一个类似的问题,我试图解决一段时间。我深入研究了 Net Core 代码库,发现了一个非常有助于在运行时调用方法而无需强类型化的类。

https://github.com/dotnet/extensions/blob/ff87989d893b000aac1bfef0157c92be1f04f714/shared/Microsoft.Extensions.ObjectMethodExecutor.Sources/ObjectMethodExecutor.cs

ObjectMethodExecutor 允许您使用对象的名称调用对象的方法。使用示例如下:

var methodInfo = [myInterface].GetMethod("[method-you-want-call]");
var classTypeInfo = [myClass].GetTypeInfo();
var executor = ObjectMethodExecutor.Create(methodInfo, classTypeInfo);

await executor.ExecuteAsync(handler, new[] { [data-you-want-to-pass-to-your-object] });

它在 SignalR 代码库中广泛使用,用于将 SignalR 消息与集线器上的内部方法进行匹配。它经过高度优化,并具有允许调用异步方法的额外好处

【讨论】:

    猜你喜欢
    • 2018-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多