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
}