简体   繁体   English

C#:使用可选参数和命名参数覆盖方法:意外结果

[英]C# : overriding Method with optional parameters & named parameters : Unexpected Result

I have two classes FirstProcess and Second Process 我有两个类FirstProcess和Second Process

public class FirstProcess
    {
        public virtual void Calculate(int x, int y)
        {
            Console.WriteLine("First Process  X :{0} and Y{1}", x, y);
        }
    }
    public class SecondProcess : FirstProcess
    {

        public override void Calculate(int y, int x)
        {
            Console.WriteLine("Second Process X :{0} and Y :{1}", x, y);
        }
    }

I have called the calculate method like below 我已经调用了如下的计算方法

  var secondProcess = new SecondProcess();
            var firstProcess = (FirstProcess) secondProcess;

            secondProcess.Calculate(x: 1, y: 2);
            firstProcess.Calculate(x: 1, y: 2);

Output 产量

Second Process X : 1 and Y:2 第二个过程X:1和Y:2

Second Process X : 2 and Y:1 第二个过程X:2和Y:1

I got unexpected result that X=2 and Y =1.How .Net handle this scenario? 我得到了意想不到的结果,X = 2和Y = 1.How .Net处理这种情况? Why .net give priority to named parameter? 为什么.net优先使用命名参数?

Argument binding for the method call firstProcess.Calculate(x: 1, y: 2) is done at compile time , but method dispatch is done at runtime because the method is virtual . 方法调用firstProcess.Calculate(x: 1, y: 2)参数绑定在编译时完成,但方法调度在运行时完成因为该方法是virtual

In order to compile the method call, the compiler sees x: 1, y: 2 and needs to resolve this named argument list to a sequentially indexed argument list in order to emit the appropriate IL (push the arguments on the stack in the right order, then call method). 为了编译方法调用,编译器看到x: 1, y: 2并且需要将此命名参数列表解析为顺序索引的参数列表,以便发出适当的IL(按正确的顺序推送堆栈上的参数) ,然后调用方法)。

In addition to the named argument list there is one more piece of information available to the compiler: the static type of firstProcess , which is FirstProcess . 除了命名参数列表之外,编译器还有另外一条信息: firstProcess静态类型,即FirstProcess Now me and you both know that at runtime this is going to be a SecondProcess instance, but the compiler doesn't know that (at least in the general case). 现在我和你们都知道在运行时这将是一个SecondProcess实例,但编译器不知道(至少在一般情况下)。 So it looks up the parameter list of FirstProcess.Calculate and sees that x is the first argument, y is the second. 因此,它查找FirstProcess.Calculate的参数列表,并看到x是第一个参数, y是第二个参数。 This makes it compile your code as if you had written 这使得它可以像编写代码一样编译代码

firstProcess.Calculate(1, 2);

At runtime , the arguments 1 and 2 are pushed on the stack and a virtual call is made to Calculate . 运行时 ,参数12被推入堆栈,虚拟调用将进行Calculate Of course this ends up calling SecondProcess.Calculate , but the parameter names have not survived the transition to runtime. 当然,这最终会调用SecondProcess.Calculate ,但参数名称在转换到运行SecondProcess.Calculate仍未存活。 SecondProcess.Calculate accepts 1 as its first argument ( y ) and 2 as its second argument ( x ), leading to the observed result. SecondProcess.Calculate接受1作为其第一个参数( y ),将2作为其第二个参数( x ),从而导致观察到的结果。

As an aside, this is also what happens when you use default argument values: 顺便说一句,这也是使用默认参数值时发生的情况:

public class FirstProcess
{
    public virtual void Calculate(int x = 10)
    {
        Console.WriteLine("First Process  X :{0}", x);
    }
}

public class SecondProcess : FirstProcess
{
    public override void Calculate(int x = 20)
    {
        Console.WriteLine("Second Process  X :{0}", x);
    }
}

var secondProcess = new SecondProcess();
var firstProcess = (FirstProcess) secondProcess;

secondProcess.Calculate(); // "Second Process X: 20"
firstProcess.Calculate();  // "Second Process X: 10"

The moral of the story: named and default arguments are convenient, but the way they are (necessarily) implemented leaves you open to unpleasant surprises. 故事的寓意:命名和默认参数都很方便,但它们(必然)实现的方式让你容易受到不愉快的惊喜。 Use them when they offer real tangible benefits, not whenever you can. 当它们提供真正有形的好处时使用它们,而不是在可能的时候。

When resolving named parameters, the compiler uses the static type of the method being called, not the dynamic type. 解析命名参数时,编译器使用被调用方法的静态类型,而不是动态类型。

Therefore in your example, x refers to the first parameter and y to the second parameter. 因此,在您的示例中, x表示第一个参数, y表示第二个参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM