Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

.net

I have two classes FirstProcess and 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

Second Process X : 2 and Y:1

I got unexpected result that X=2 and Y =1.How .Net handle this scenario? Why .net give priority to named parameter?

like image 407
Jameel Moideen Avatar asked Aug 29 '13 09:08

Jameel Moideen


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


1 Answers

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.

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).

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. 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). So it looks up the parameter list of FirstProcess.Calculate and sees that x is the first argument, y is the second. 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. Of course this ends up calling SecondProcess.Calculate, but the parameter names have not survived the transition to runtime. SecondProcess.Calculate accepts 1 as its first argument (y) and 2 as its second argument (x), leading to the observed result.

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.

like image 85
Jon Avatar answered Oct 13 '22 03:10

Jon