我有两个类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);
}
}
Run Code Online (Sandbox Code Playgroud)
我已经调用了如下的计算方法
var secondProcess = new SecondProcess();
var firstProcess = (FirstProcess) secondProcess;
secondProcess.Calculate(x: 1, y: 2);
firstProcess.Calculate(x: 1, y: 2);
Run Code Online (Sandbox Code Playgroud)
产量
第二个过程X:1和Y:2
第二个过程X:2和Y:1
我得到了意想不到的结果,X = 2和Y = 1.How .Net处理这种情况?为什么.net优先使用命名参数?
方法调用的参数绑定在编译时firstProcess.Calculate(x: 1, y: 2)完成,但方法调度在运行时完成,因为方法是.virtual
为了编译方法调用,编译器看到x: 1, y: 2并需要将此命名参数列表解析为顺序索引的参数列表,以便发出适当的IL(按正确顺序推送堆栈中的参数,然后调用方法).
除了命名参数列表之外,编译器还有另外一条信息:静态类型firstProcess,即FirstProcess.现在我和你都知道在运行时这将是一个SecondProcess实例,但编译器不知道(至少在一般情况下).所以它查找参数列表FirstProcess.Calculate并看到这x是第一个参数,y是第二个参数.这使得它可以像编写代码一样编译代码
firstProcess.Calculate(1, 2);
Run Code Online (Sandbox Code Playgroud)
在运行时,参数1和2被推入堆栈并进行虚拟调用Calculate.当然这最终会调用SecondProcess.Calculate,但参数名称在转换到运行时后仍未存活.SecondProcess.Calculate接受1作为其第一个参数(y)和2第二个参数(x),导致观察到的结果.
顺便说一句,这也是使用默认参数值时发生的情况:
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"
Run Code Online (Sandbox Code Playgroud)
故事的寓意:命名和默认参数都很方便,但它们(必然)实现的方式让你容易受到不愉快的惊喜.当它们提供真正有形的好处时使用它们,而不是在可能的时候使用它