gpt4 book ai didi

c# - 在方法覆盖中更改 params 修饰符

转载 作者:可可西里 更新时间:2023-11-01 08:50:01 26 4
gpt4 key购买 nike

我知道 params 修饰符(将数组类型的一个参数转换为所谓的“参数数组”)不是方法签名的一部分。现在考虑这个例子:

class Giraffid
{
public virtual void Eat(int[] leaves)
{
Console.WriteLine("G");
}
}
class Okapi : Giraffid
{
public override void Eat(params int[] leaves)
{
Console.WriteLine("O");
}
}

编译时没有警告。然后说:

var okapi = new Okapi();
okapi.Eat(2, 4, 6); // will not compile!

给出错误(方法“Eat”没有重载需要 3 个参数)。

现在,我知道编译器将 params 修饰符转换为 System.ParamArrayAttribute 对相关参数的应用。通常,将一组属性应用于虚方法的参数,然后在派生类的重写方法中用一组不同的属性修饰“相应”参数是没有问题的。

然而,编译器选择默默地忽略我的 params 关键字。相反,如果反过来,将 params 应用于基类 Giraffid 中的参数,然后在 Okapi 的 override 中省略关键字,编译器选择用 System.ParamArrayAttribute 修饰两个方法。当然,我用 IL DASM 验证了这些事情。

我的问题:

这是记录在案的行为吗?我已经彻底搜索了 C# 语言规范,但没有找到任何提及。

我可以说至少 Visual Studio 开发环境对此感到困惑。在上述方法调用中键入 2, 4, 6 时,intellisense 会在提示中显示 void Okapi.Eat(params int[] leaves).


为了比较,我还尝试实现一个接口(interface)方法并更改接口(interface)和实现类中 params 的存在/不存在,我尝试定义一个委托(delegate)类型并更改 params 或不在委托(delegate)类型定义或其方法组中分配给我的委托(delegate)类型变量的方法。在这些情况下,完全可以更改 params-ness。

最佳答案

编译器的行为是正确的,但这有点困惑。我希望这至少是一个警告。

毫不奇怪,您在规范中找不到它说这是正确的地方。相关位是:

The binding-time processing of a method invocation of the form M(A), where M is a method group, and A is an optional argument-list, consists of the following steps: The set of candidate methods for the method invocation is constructed. For each method F associated with the method group M, if F is non-generic, F is a candidate when M has no type argument list, and F is applicable with respect to A.

“与方法组 M 关联的方法”是什么?那么,首先,什么是方法组?

A method group, which is a set of overloaded methods resulting from a member lookup...

好的,那么成员查找规则是什么?

Otherwise, the set consists of all accessible members named N in T, including inherited members and the accessible members named N in object. Members that include an override modifier are excluded from the set.

添加了强调。

这里的实际结果是,出于重载决议的目的,被覆盖的方法被认为是最初声明的方法,而不是被覆盖. 不幸的是,在这种情况下违反了这条规则:

virtual void M(int x, int y) { }
...
override void M(int y, int x) { }
...
M(x = 1, y = 2);

重载解析使用来自更多派生 版本的名称。这是一个不幸的结果,因为命名参数是在游戏中很晚才添加的。

简而言之:为了确定一个方法是否为“params”,分析是在原始方法上进行的,而不是在覆盖方法上进行的。

如果编译器在这里给你一个警告就好了。

can say that at least the Visual Studio development environment is confused about this

正确。 IntelliSense 层始终显示重写方法的方法信息,而不是被重写的方法。研究表明,当方法看起来像是最初声明的方法而不是覆盖方法时,用户会感到困惑。当然,正如我之前提到的,这些是您要用于命名参数的参数名称。

关于c# - 在方法覆盖中更改 params 修饰符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27843804/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com