简体   繁体   English

RuntimeBinderException 将泛型类型上的方法作为动态调用

[英]RuntimeBinderException invoking a method on a generic type as dynamic

I'm trying to invoke a method on a generic type (generic is also an argument to invoking method) and are hitting RuntimeBinderException that I don't really see how to work around.我正在尝试在泛型类型上调用一个方法(泛型也是调用方法的一个参数)并且遇到了RuntimeBinderException ,我真的不知道如何解决。

As you can see in below example the instance returns the MyHandler instance (as a dynamic ) which I expect to get invoked, but without explicit conversion to the generic type of the DTO ( as MyDto ) it will crash.正如您在下面的示例中看到的那样,该实例返回MyHandler实例(作为dynamic ),我希望调用它,但是如果没有显式转换为 DTO 的泛型类型( as MyDto ),它将崩溃。 And my requirement is to determine the type in runtime (as I see the JsonConvert.DeserializeObject(data, type) does, until the point of invocation).我的要求是确定运行时的类型(正如我看到的JsonConvert.DeserializeObject(data, type)所做的那样,直到调用点)。

static async Task Main(string[] args)
{
    string dataType = typeof(MyDto).AssemblyQualifiedName;
    string data = JsonConvert.SerializeObject(new MyDto());

    var type = Type.GetType(dataType);
    var dto = JsonConvert.DeserializeObject(data, type);
    var handler = GetHandler();

    await handler.HandleMessageAsync(dto, CancellationToken.None); // throws the RuntimeBinderException   
    await handler.HandleMessageAsync(dto as MyDto, CancellationToken.None); // is able to invoke MyHandler.HandleMessageAsync

}

public static dynamic GetHandler()
{
    // this is simplified logic for locating a handler instance.
    return new MyHandler();
}

The exception thrown in the 1st invocation from example is示例的第一次调用中引发的异常是

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'The best overloaded method match for 'ConsoleApp.MessageHandlerBase<ConsoleApp.MyDto>.HandleMessageAsync(ConsoleApp.MyDto, System.Threading.CancellationToken)' has some invalid arguments' Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:'ConsoleApp.MessageHandlerBase<ConsoleApp.MyDto>.HandleMessageAsync(ConsoleApp.MyDto, System.Threading.CancellationToken)' 的最佳重载方法匹配有一些无效参数'

I don't see how the conversion can make a change to the DTO as they are the same type.我看不到转换如何更改 DTO,因为它们是相同的类型。 So, my question is how I can succeed invoking the method completely dynamically?所以,我的问题是我怎样才能成功地完全动态地调用该方法?

This is the simplified DTO and handler service class hierarchy of the real implementation:这是实际实现的简化 DTO 和处理程序服务 class 层次结构:

public class MyDto 
{
    public int Prop1 { get; set; } = 1;
}

public interface IMessageHandler<in T> where T : class
{
    Task HandleMessageAsync(T dto, CancellationToken cancellationToken);
}

public class MyHandler : IMessageHandler<MyDto>
{
    public Task HandleMessageAsync(MyDto dto, CancellationToken cancellationToken)
    {
        Console.WriteLine("OnError called from " + this);
        return Task.CompletedTask;
    }
}

Can you please try changing type of dto variable from object to dynamic as below -您能否尝试将 dto 变量的类型从 object 更改为动态,如下所示 -

dynamic dto = JsonConvert.DeserializeObject(data, type);

The final code should something like this -最终的代码应该是这样的 -

static async Task Main(string[] args)
{
    string dataType = typeof(MyDto).AssemblyQualifiedName;
    string data = JsonConvert.SerializeObject(new MyDto());

    var type = Type.GetType(dataType);
    dynamic dto = JsonConvert.DeserializeObject(data, type); // declare as dynamic instead of var (declaring as var would default to object type)
    var handler = GetHandler();

    await handler.HandleMessageAsync(dto, CancellationToken.None); // throws the RuntimeBinderException   
    await handler.HandleMessageAsync(dto as MyDto, CancellationToken.None); // is able to invoke MyHandler.HandleMessageAsync

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM