c# - 为什么编译器选择通用方法而不是特定方法?
问题描述
我有这个服务接口。
public interface IService
{
Task SetAsync(string key, string value, TimeSpan? expiration = null);
Task SetAsync<T>(string applicationName, string key, T value, TimeSpan? expiration = null);
}
我想通过这样做来调用第一种方法。
service.SetAsync("Key", "Value", TimeSpan.FromMinutes(1));
方法调用与第一种方法的合约 100% 匹配。然而,编译器通过假设TimeSpan
是我的泛型类型来选择第二种方法。
为什么会这样?
解决方案
这遵循 ECMA C# 5 标准第 12.6.4.3 节中“更好的功能成员”的规则:
为了确定更好的函数成员,构造了一个精简的参数列表 A,其中仅包含参数表达式本身,按照它们在原始参数列表中出现的顺序。
每个候选函数成员的参数列表按以下方式构造:
- 如果函数成员仅适用于扩展形式,则使用扩展形式。
- 从参数列表中删除没有对应参数的可选参数
- 参数被重新排序,以便它们出现在与参数列表中相应参数相同的位置。
因此,在这一点上,我们正在有效地比较这两种方法:
Task SetAsync(string key, string value, TimeSpan? expiration);
Task SetAsync<T>(string applicationName, string key, T value);
(在泛型方法版本中,expiration
参数没有对应的参数,因此从参数列表中删除。)
参数列表是"Key", "Value", TimeSpan.FromMinutes(1)
,并且T
推断为TimeSpan
。
下一个:
给定一个带有一组参数表达式 { E1, E2, ..., EN } 的参数列表 A 和两个适用的函数成员 MP 和 MQ,参数类型为 { P1, P2, ..., PN } 和 { Q1, Q2, ..., QN }, MP 被定义为比 MQ 更好的函数成员,如果
- 对于每个参数,从 EX 到 QX 的隐式转换并不比从 EX 到 PX 的隐式转换好,并且
- 对于至少一个论点,从 EX 到 PX 的转换优于从 EX 到 QX 的转换。
对于前两个参数,没有区别 - 因为它们string
无处不在。
对于第三个参数,非泛型方法的转换是 from TimeSpan
to TimeSpan?
,而泛型方法的转换是 from TimeSpan
to TimeSpan
(因为T
is TimeSpan
)。
to的恒等转换比TimeSpan
to的隐式转换“更好”(根据TimeSpan
12.6.4.4 的规则),因此对于该参数,通用方法是“更好”...泛型方法“更好”,因此总体而言泛型方法更好。TimeSpan
TimeSpan?
如果在这个阶段没有发现任何一种方法“更好”(例如,由于参数类型TimeSpan
而不是TimeSpan?
可选参数),那么非通用方法将被抢七规则确定为“更好”在这个阶段之后。但是到那时,已经选择了通用方法。
推荐阅读
- javascript - 第一次单击后不显示引导选项卡下拉菜单
- javascript - 如何在不重新加载页面的情况下更改部分 url 浏览器?
- c# - 通过 Web 链接与打开的应用程序交互
- python-3.x - 如何在 PyCharm 中安装库?
- php - laravel 6和ajax中加载更多按钮的问题
- python - RelatedObjectDoesNotExist:用户没有卖家
- audio - 仅播放来自 youtube-dl 的 M3U8 文件中的音频 ts 流
- spring-boot - 在springboot的OAuth2框架中区分来自不同客户端的请求
- c++ - 如何将多个变量读入一个节点?
- java - JavaFX WebView:自定义光标不起作用?