c# - 为什么在运行时调用重载函数时会发生 RuntimeBinderException?
问题描述
我终于制作了一个重现此错误的最小示例:
using System;
using Newtonsoft.Json;
class Program
{
public byte[] Foo(byte[] p) { return new byte[0]; }
public byte[] Foo(Guid? p) { return new byte[0]; }
static Guid? ToGuid(string s) { return s == null ? null : (Guid?)new Guid(s); }
void Bar()
{
dynamic d = JsonConvert.DeserializeObject<dynamic>("{}");
var id = d?.id?.ToString();
Foo(ToGuid(id));
}
static void Main(string[] args)
{
new Program().Bar();
}
}
奇怪的是,当 d.id 为空(或不是字符串)时,它在运行时调用 Foo 时崩溃,说它无法解析要调用的 Foo 版本(以下方法或属性之间的调用不明确)。为什么这不是在编译时解决的呢?不应该有dynamic
什么不同,我可以看到,事实上更奇怪的是,如果我在它按预期工作(Guid?)
之前添加一个显式强制转换 " " ToGuid...
,同样如果我把它写成:
Guid? id = ToGuid(d.id?.ToString());
Foo(id)
无论如何,这实际上更有意义。如果我将“var”更改为“string”,它也可以正常工作。
我注意到异常最初是从“System.Linq.Expressions.dll”引发的,这有点奇怪。完整的堆栈跟踪基本上是:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:以下方法或属性之间的调用不明确:CallSite.Target(Closure、CallSite、 FooService , 对象)
异常源是“匿名托管的 DynamicMethods 程序集”
解决方案
现在我们有了var
变体,我可以重现这个问题。问题是null
s。您可能认为 of 的返回类型ToGuid
必须是 a Guid?
,因为您假设知道编译器无法使用。就它而言,Bar
它正在查看id
with type dynamic
1。这意味着它将假设返回的任何 ToGuid
内容都将存储在dynamic
临时变量中。
在这种情况下,它返回null
并且在幕后,dynamic
只是object
. 那时,我们已经丢失了任何关于返回类型的编译时类型信息ToGuid
。如果不是null
,在它解决之前Foo
它会有效地调用GetType
实例。但这在这里是不可能的。它有null
两个同样好/坏的候选人,它可以通过null
参考来调用。就好像你写的一样Foo(null);
(在编译时会产生等效的错误)。
插入显式强制转换 -在调用点为Foo((Guid?)ToGuid(id));
运行时提供足够的信息,以便能够明确地选择Foo
您希望它选择的正确重载。
1请记住,无论id
on 属性的类型d
是什么,它都可能有一种ToString
方法可以将object
. 它不能假设它也string
返回id
一个dynamic
。
推荐阅读
- mysql - mysql order by sum(column) 由具有自连接的另一列分组
- selenium - Jmeter 采样器参数:为什么访问第二个参数时数组索引超出范围?
- spring - Spring boot:我不断收到 org.springframework.security.authentication.BadCredentialsException:凭据错误,我不知道为什么
- java - 如何在 Java 中加快 zip 文件中条目的解析
- c# - 实现一个使用路由系统的 HtmlHelper 扩展
- php - 急切加载不会返回任何内容
- javascript - 如何通过angulartics2跟踪`ecommerce:addItem`或`ecommerce:addTransaction`?
- c# - 如何为 HTML 缓存 mp4 视频
- sql - PostgreSQL - 逐秒创建视图
- xml - 我什么时候应该在数据库上使用 XML 文件?如果在 XML 文件中存储大数据效率低下,那么 XML 数据库能解决这个问题吗?