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

C# RuntimeBinderException将泛型类型上的方法作为动态调用,c#,.net-core,C#,.net Core,我试图在泛型类型上调用一个方法(泛型也是调用方法的参数),但遇到了RuntimeBinderException,我真的不知道如何解决这个问题 正如您在下面的示例中所看到的,该实例返回了MyHandler实例(作为dynamic),我希望调用该实例,但如果不显式转换为DTO的泛型类型(作为MyDto),它将崩溃。我的要求是在运行时确定类型(正如我看到的JsonConvert.DeserializeObject(数据,类型)所做的,直到调用点) 在来自示例的第一次调用中引发的异常是 Microsof

我试图在泛型类型上调用一个方法(泛型也是调用方法的参数),但遇到了
RuntimeBinderException
,我真的不知道如何解决这个问题

正如您在下面的示例中所看到的,该实例返回了
MyHandler
实例(作为
dynamic
),我希望调用该实例,但如果不显式转换为DTO的泛型类型(
作为MyDto
),它将崩溃。我的要求是在运行时确定类型(正如我看到的
JsonConvert.DeserializeObject(数据,类型)
所做的,直到调用点)

在来自示例的第一次调用中引发的异常是

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:“与“ConsoleApp.MessageHandlerBase.HandleMessageAsync(ConsoleApp.MyDto,System.Threading.CancellationToken)”匹配的最佳重载方法具有一些无效参数”

我不知道转换如何改变DTO,因为它们是相同的类型。所以,我的问题是如何成功地完全动态地调用该方法

这是实际实现的简化DTO和处理程序服务类层次结构:

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;
    }
}
公共类MyDto
{
公共int Prop1{get;set;}=1;
}
公共接口IMessageHandler,其中T:class
{
任务HandleMessageAsync(T dto,CancellationToken CancellationToken);
}
公共类MyHandler:IMessageHandler
{
公共任务HandleMessageAsync(MyDto dto、CancellationToken CancellationToken)
{
Console.WriteLine(“从“+this”调用OnError);
返回Task.CompletedTask;
}
}

请尝试将dto变量的类型从object更改为dynamic,如下所示-

dynamic dto = 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);
    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

}

如果运行时没有可用的
MyDto
,如何调用
HandleMessageAsync(MyDto,…)
?你是否真的运行了你的示例,或者可能是当
MyDto
不可用时失败了,而当
MyDto
可用时就没事了,不管类型如何?@canton7我认为“问题是我在运行时没有可用的静态类型。”这是误导。我把那部分删掉了。我想说的是,我需要用运行时中指定的类型反序列化该类型。(JsonConvert.DeserializeObject(数据,类型)part)你能创建一个我们可以运行的吗?@canton7运行这个的所有代码都在那里。谢谢。你有什么解释吗?这让人惊讶:)当处理对象类型时,在对其执行任何操作时需要显式转换,而使用动态时则不需要转换。这是因为.net运行时在计算对象类型时强制执行其他规则(例如,当将对象分配给任何类型时,会出现无效的强制转换编译时错误),但在动态情况下,这些规则是宽松的(将动态分配给任何类型时,不会出现编译时错误,如果无法强制转换对象,则会出现运行时错误)。总之,对于对象,显式转换是必需的,而对于动态转换则不是。
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

}