visual studio 2013 和 2015 之间重载方法行为的变化
Changes on overloaded method behaviour between visual studio 2013 and 2015
Visual Studio 2013 和 2015 有很大的问题。在一个 class 中,我定义了这两种方法:
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 规范似乎尚未发布,所以这是我能做的最好的。这也是援引坎宁安定律的尝试。
作为初步,在规范的 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
.
- 这里没有区别;两者都是扩展形式
- 否则,如果
Mp
比Mq
声明的参数多,那么Mp
比Mq
好。如果这两种方法都有 params
数组并且仅适用于它们的扩展形式,就会发生这种情况。
- 这一项不是 100%。我们的两个参数列表都使用原始函数定义中的两个参数。我认为这 仅 旨在区分一种情况,即两个参数都进入同一个
params
数组,一个进入数组,一个进入普通参数。
- 否则,如果
Mp
的所有参数都有相应的参数,而默认参数需要替换 Mq
中的至少一个可选参数,那么 Mp
是优于 Mq
.
- 啊哈!我们的第一个参数列表缺少
optWherePart
,它需要一个默认参数,所以第二个参数列表更好!所以VS2015是错误的!
...但是等等。最后一颗子弹是什么意思? Mp
和 Mq
是专门的参数列表,其中 [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 中的相同。
Visual Studio 2013 和 2015 有很大的问题。在一个 class 中,我定义了这两种方法:
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 规范似乎尚未发布,所以这是我能做的最好的。这也是援引坎宁安定律的尝试。
作为初步,在规范的 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
.- 这里没有区别;两者都是扩展形式
- 否则,如果
Mp
比Mq
声明的参数多,那么Mp
比Mq
好。如果这两种方法都有params
数组并且仅适用于它们的扩展形式,就会发生这种情况。- 这一项不是 100%。我们的两个参数列表都使用原始函数定义中的两个参数。我认为这 仅 旨在区分一种情况,即两个参数都进入同一个
params
数组,一个进入数组,一个进入普通参数。
- 这一项不是 100%。我们的两个参数列表都使用原始函数定义中的两个参数。我认为这 仅 旨在区分一种情况,即两个参数都进入同一个
- 否则,如果
Mp
的所有参数都有相应的参数,而默认参数需要替换Mq
中的至少一个可选参数,那么Mp
是优于Mq
.- 啊哈!我们的第一个参数列表缺少
optWherePart
,它需要一个默认参数,所以第二个参数列表更好!所以VS2015是错误的!
- 啊哈!我们的第一个参数列表缺少
...但是等等。最后一颗子弹是什么意思? Mp
和 Mq
是专门的参数列表,其中 [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 中的相同。