visual studio 2013 和 2015 之间重载方法行为的变化

Changes on overloaded method behaviour between visual studio 2013 and 2015

Visual Studio 2013 和 2015 有很大的问题。在一个 class 中,我定义了这两种方法:

  1. public List<T> LoadData<T>(string connectionStringName = "", string optWherePart = "", params object[] parameter)
  2. public List<T> LoadData<T>(string optWherePart, params object[] parameter)

我只想这样调用第二种方法:

....LoadData<Config_Info>("ConfigName LIKE 'Version' AND UserName LIKE '' AND PlugInName Like ?", parameter: ProductName);

如果我在 Visual Studio 2013 年去定义,我会来到第二个方法声明,但在 Visual Studio 2015 年,我会来到第一个。两种解决方案都是 完全一样。

即使编译结果不同,所以如果我用 VS 2015 编译相同的解决方案,程序将停止运行。

这是一个非常奇怪的行为。

有没有人知道有什么区别?

这是基于 C# 5 规范,但由于 C# 6 规范似乎尚未发布,所以这是我能做的最好的。这也是援引坎宁安定律的尝试。


作为初步,在规范的 s7.5.3.1 ("Applicable Function Member") 语言中,两个函数成员都适用(如果另一个不存在,则可以调用其中一个)它们的扩展形式(params object[] 无法通过 string ProductName 实现,因此被转换为 object 参数)。

因此我们继续进行 s7.5.3.2 ("Better Function Member") 以确定调用两者中哪一个是更好的函数。


首先,构造了一个精简的参数列表 A,仅包含参数表达式本身,按照它们在原始参数列表中出现的顺序:

  • { string "ConfigName [...]", string ProductName }

接下来,[p]每个候选函数成员的参数列表按以下方式构造:

  • 如果函数成员仅适用于展开形式,则使用展开形式。
  • 从参数列表中删除没有对应参数的可选参数
  • 参数被重新排序,以便它们与参数列表中的相应参数出现在相同的位置。

这给了我们以下信息:

  • { string connectionStringName, object parameter }optWherePart 已删除,params 已扩展)
  • { string optWherePart, object parameter }params 展开)

然后我们进行一系列比较,以确定其中哪个是 更好的函数成员。调用一个 Mp 和一个 Mq,如下所示:

  • 如果Mp是非泛型方法而Mq是泛型方法,那么Mp优于Mq
    • 这里没有区别
  • 否则,如果 Mp 适用于其正常形式,而 Mq 具有参数数组且仅适用于其扩展形式,则 Mp 是优于 Mq.
    • 这里没有区别;两者都是扩展形式
  • 否则,如果MpMq声明的参数多,那么MpMq好。如果这两种方法都有 params 数组并且仅适用于它们的扩展形式,就会发生这种情况。
    • 这一项不是 100%。我们的两个参数列表都使用原始函数定义中的两个参数。我认为这 旨在区分一种情况,即两个参数都进入同一个 params 数组,一个进入数组,一个进入普通参数。
  • 否则,如果 Mp 的所有参数都有相应的参数,而默认参数需要替换 Mq 中的至少一个可选参数,那么 Mp 是优于 Mq.
    • 啊哈!我们的第一个参数列表缺少 optWherePart,它需要一个默认参数,所以第二个参数列表更好!所以VS2015是错误的!

...但是等等。最后一颗子弹是什么意思? MpMq 是专门的参数列表,其中 [o] 没有相应参数的可选参数被删除 。他们中的任何一个都不可能 有相应的论点 因为如果他们没有,他们就会被删除。


总之,我分不清这是旧编译器、新编译器...还是 C# 规范中的错误。

我发现 blog post by SLaks 似乎也认为旧行为是一个错误。该博客指出,Roslyn 已通过使编译器失败来解决此问题,但我不再看到这种情况。也许他们改变了主意?


编辑:更新!我的 Roslyn bug report resulted in a change to the compiler 确保在这种情况下选择 second 重载。这似乎是因为 default arguments need to be substituted 上面的措辞。我仍然认为规范不明确,所以我很失望只做了代码更改(而不是规范更改,甚至没有讨论为什么第二个重载更好),但至少 VS2015 运行时行为是现在与 VS2013 中的相同。