为什么这样做?方法重载+方法重写+多态

kas*_*sey 12 c# polymorphism overriding overloading

在以下代码中:

public abstract class MyClass
{
public abstract bool MyMethod(
        Database database,
        AssetDetails asset,
        ref string errorMessage);
}

public sealed class MySubClass : MyClass
{
    public override bool MyMethod(
        Database database,
        AssetDetails asset,
        ref string errorMessage)
    {
        return MyMethod(database, asset, ref errorMessage);
    }

    public bool MyMethod(
        Database database,
        AssetBase asset,
        ref string errorMessage)
    {
    // work is done here
}
}
Run Code Online (Sandbox Code Playgroud)

其中AssetDetails是AssetBase的子类.

为什么第一个MyMethod在传递AssetDetails时会在运行时调用第二个,而不是陷入递归的无限循环?

ang*_*son 10

C#将解析对其他实现的调用,因为调用对象上的方法(其中该对象的类具有自己的实现)将优先于被覆盖或继承的实现.

这可能会导致细微且难以发现的问题,就像您在此处所展示的那样.

例如,尝试这段代码(先读取它,然后编译并执行它),看看它是否符合你的预期.

using System;

namespace ConsoleApplication9
{
    public class Base
    {
        public virtual void Test(String s)
        {
            Console.Out.WriteLine("Base.Test(String=" + s + ")");
        }
    }

    public class Descendant : Base
    {
        public override void Test(String s)
        {
            Console.Out.WriteLine("Descendant.Test(String=" + s + ")");
        }

        public void Test(Object s)
        {
            Console.Out.WriteLine("Descendant.Test(Object=" + s + ")");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Descendant d = new Descendant();
            d.Test("Test");
            Console.In.ReadLine();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您声明变量的类型Base而不是类型Descendant,则调用将转到另一个方法,尝试更改此行:

Descendant d = new Descendant();
Run Code Online (Sandbox Code Playgroud)

对此,并重新运行:

Base d = new Descendant();
Run Code Online (Sandbox Code Playgroud)

那么,你怎么能真正设法打电话Descendant.Test(String)呢?

我的第一次尝试看起来像这样:

public void Test(Object s)
{
    Console.Out.WriteLine("Descendant.Test(Object=" + s + ")");
    Test((String)s);
}
Run Code Online (Sandbox Code Playgroud)

这对我没有好处,而是Test(Object)一次又一次地调用最终的堆栈溢出.

但是,以下工作.因为,当我们将d变量声明为Base类型时,我们最终调用正确的虚方法,我们也可以使用该技巧:

public void Test(Object s)
{
    Console.Out.WriteLine("Descendant.Test(Object=" + s + ")");
    Base b = this;
    b.Test((String)s);
}
Run Code Online (Sandbox Code Playgroud)

这将打印出来:

Descendant.Test(Object=Test)
Descendant.Test(String=Test)
Run Code Online (Sandbox Code Playgroud)

你也可以从外面做到这一点:

Descendant d = new Descendant();
d.Test("Test");
Base b = d;
b.Test("Test");
Console.In.ReadLine();
Run Code Online (Sandbox Code Playgroud)

会打印出来的.

首先需要意识到这个问题,这完全是另一回事.


tva*_*son 5

请参阅有关成员查找过载解决方案的C#语言规范部分.由于成员查找的规则,派生类的覆盖方法不是候选方法,并且基类方法不是基于重载决策规则的最佳匹配.

第7.3节

首先,构造在T中声明的名为N的所有可访问(第3.5节)成员的集合,并构造T的基本类型(第7.3.1节).包含覆盖修饰符的声明将从集合中排除.如果没有名为N的成员存在且可访问,则查找不会产生匹配,并且不评估以下步骤.

第7.4.2节:

这些上下文中的每一个都以其自己独特的方式定义候选函数成员集和参数列表,如上面列出的部分中详细描述的.例如,方法调用的候选集不包括标记为override的方法(第7.3节),如果派生类中的任何方法适用,则基类中的方法不是候选方法(第7.5.5.1节).(强调我的)