【问题标题】:Changes on overloaded method behaviour between visual studio 2013 and 2015Visual Studio 2013 和 2015 之间重载方法行为的变化
【发布时间】:2015-10-30 20:46:10
【问题描述】:

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

  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 编译相同的解决方案,程序就会停止工作。

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

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

【问题讨论】:

  • ProductName 的类型是什么?
  • 我是一个简单的字符串。
  • 好的,所以我在 VS2010 上尝试了这个,Go To Definition 转到了#2(但我没有运行它,所以无法确认它调用的是哪个。)我在家里试过了VS2015 和 Go To Definition 转到 #1,Run 转到 #1。我在 VS2013 上在家尝试过,Go To Definition 转到 #2 并运行转到 #2。要么是在 2013 年的 Intellisense 中存在一个在 2015 年修复的错误,要么是 Roslyn 被破坏并且以某种方式安装 2015 破坏了 2013 编译器但不是 Intellisense
  • 我应该报告一些地方吗?非常感谢!
  • Here 我猜。我认为这 编译器中的一个错误;我正要写一个答案。

标签: c# visual-studio visual-studio-2013 visual-studio-2015 go-to-definition


【解决方案1】:

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


作为初步,在规范的 s7.5.3.1(“适用函数成员”)的语言中,两个函数成员都适用(如果另一个不存在,则可以调用其中一个)形式(params object[] 不能由 string ProductName 实现,因此转换为 object 参数)。

因此,我们转到 s7.5.3.2(“更好的函数成员”),以确定两者中哪一个是更好的函数调用。


首先,构造一个精简的参数列表 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 有一个 params 数组并且仅适用于其扩展形式,则 Mp 优于 Mq
    • 这里没有区别;两者都是展开形式
  • 否则,如果Mp 的声明参数比Mq 多,那么MpMq 好。如果这两种方法都有 params 数组并且仅适用于它们的扩展形式,则可能会发生这种情况。
    • 这个不是 100%。我们的两个参数列表都使用原始函数定义中的 2 个参数。我认为这是为了区分两个参数进入同一个params数组的一种情况和一个进入数组而一个进入普通参数的情况。
  • 否则,如果Mp 的所有参数都有对应的参数,而默认参数需要替换Mq 中的至少一个可选参数,那么Mp 优于Mq
    • 啊哈!我们的第一个参数列表缺少optWherePart,它需要一个默认参数,所以第二个参数列表更好!所以VS2015错了!

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


总之,我不知道这是旧编译器、新编译器……还是 C# 规范中的错误。

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


编辑:更新!我的Roslyn bug report 生成了change to the compiler,以确保在这种情况下选择second 重载。这似乎是因为上面的 默认参数需要替换 措辞。我仍然认为规范是模棱两可的,所以我很失望只进行了代码更改(而不是规范更改,甚至没有讨论为什么第二个重载更好),但至少 VS2015 运行时行为是现在和 VS2013 中的一样。

【讨论】:

  • 想不出更好的答案! +1!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-21
  • 2016-03-02
  • 2015-10-13
  • 2015-10-10
  • 1970-01-01
  • 2015-08-13
相关资源
最近更新 更多