Visual Studio 2013和2015有大问题。在一个类中,我定义了这两种方法:
public List<T> LoadData<T>(string connectionStringName = "", string optWherePart = "", params object[] parameter)
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规范似乎还没有发布,这是我能做的最好的事情。这也是调用Cunningham定律的一种尝试。
初步而言,在规范的s7.5.3.1("适用函数成员"(的语言中,两个函数成员都以其扩展形式适用(如果另一个不存在,则可以调用其中一个((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
具有params数组并且仅以其展开形式适用,则Mp
优于Mq
- 这里没有区别;两者都是展开形式
-
否则,如果
Mp
具有比Mq
更多的声明参数,则Mp
比Mq
更好。如果这两种方法都有params
数组,并且仅适用于它们的扩展形式,则可能发生这种情况- 这不是100%。我们的两个参数列表都使用了原始函数定义中的2个参数。我认为这只是用于区分两个参数进入同一
params
数组的一种情况,以及一个进入数组和一个进入正常参数的情况
- 这不是100%。我们的两个参数列表都使用了原始函数定义中的2个参数。我认为这只是用于区分两个参数进入同一
-
否则,如果
Mp
的所有参数都有相应的参数,而默认参数需要替换Mq
中的至少一个可选参数,则Mp
比Mq
更好- 啊哈!我们的第一个参数列表缺少
optWherePart
,它需要一个默认参数,所以第二个参数列表更好!所以VS2015是错误的
- 啊哈!我们的第一个参数列表缺少
但是等一下。最后一颗子弹是什么意思?Mp
和Mq
是特定的参数列表,其中删除了没有相应参数的可选参数。他们中的任何一个都不可能有相应的参数,因为如果没有,他们就会被删除。
总之,我不知道这是旧编译器的错误,还是新编译器的错误。。。或者C#规范。
我发现SLaks的一篇博客文章似乎也认为这种旧行为是一个错误。博客上说Roslyn已经通过使编译器失败来解决了这个问题,我现在已经看不到了。也许他们改变了主意?
编辑:更新!我的Roslyn错误报告导致对编译器进行了更改,以确保在这种情况下,选择第二个重载。这似乎是因为默认参数需要替换上面的措辞。我仍然认为规范是模糊的,所以我很失望只做了一个代码更改(而不是规范更改,甚至没有讨论为什么第二个重载是更好的(,但至少VS2015运行时beaviour现在与VS2013中相同。