1

我有两个数据类:BaseDataClassDerivedDataClass,它们派生自第一个。我还有两个 Consuming 类:ConsumingBaseClassConsumingDerivedClass,它们派生自第一个。在ConsumingBaseClass我有虚拟方法DoWork,它接受DerivedDataClass并做一些工作。

ConsumingDerivedClass中,我对方法DoWork进行了覆盖,并且对接受BaseDataClass的DoWork进行了重载。当我尝试调用DoWork时,传递DerivedDataClass的实例,调用DoWork(BaseDataClass)而不是DoWork(DerivedDataClass)

有谁知道,为什么调用错误的方法?

以下代码演示了该问题:

class Program
{
    private static void Main(string[] args)
    {
        ConsumingDerivedClass x = new ConsumingDerivedClass();
        // Wrong DoWork is called - expected calling of DoWork(DerivedDataClass) but actually called DoWork(BaseDataClass)
        x.DoWork(new DerivedDataClass());
        Console.ReadKey();
    }
}

public class ConsumingBaseClass
{
    public virtual void DoWork(DerivedDataClass instance)
    {
        Console.WriteLine("ConsumingBaseClass.DoWork(DerivedDataClass); Type of argument is '{0}'", instance.GetType());
    }
}

public class ConsumingDerivedClass : ConsumingBaseClass
{
    public override void DoWork(DerivedDataClass instance)
    {
        Console.WriteLine("ConsumingDerivedClass.DoWork(DerivedDataClass); Type of argument is '{0}'", instance.GetType());
        base.DoWork(instance);
        // Some additional logic
    }

    public void DoWork(BaseDataClass instance)
    {
        Console.WriteLine("ConsumingDerivedClass.DoWork(BaseDataClass); Type of argument is '{0}'", instance.GetType());
        DerivedDataClass derivedInstance = new DerivedDataClass();
        // Some logic based on what is in baseInstacne
        derivedInstance.SomeProperty = "Value, got from some logic";

        base.DoWork(derivedInstance);
        // Some additional logic
    }
}

public class BaseDataClass
{ }

public class DerivedDataClass : BaseDataClass
{ 
    public string SomeProperty { get; set; } 
}
4

2 回答 2

7

有谁知道,为什么调用错误的方法?

根据语言规范调用正确的方法。是你的期望是错误的。

在 ConsumingDerivedClass 中,我对 DoWork 方法进行了覆盖,并且对接受 BaseDataClass 的 DoWork 进行了重载。

基本上,这就是问题所在。重载解决方案并不像您认为的那样起作用。编译器从调用目标的编译时类型开始工作,一直到基类到object. 只考虑新声明的方法(甚至没有被覆盖)。

您可以通过编写来更改将使用的重载:

((ConsumingBaseClass) x).DoWork(new DerivedDataClass());

不过,理想情况下,如果你有这么脆弱的东西,给这些方法起不同的名字是值得的。重载应该具有相同的效果,只是以不同的方式提供信息。

基本上,看看我的脑筋急转弯页面上的第一个问题,以及第一个答案的详细信息。我还有一篇关于重载解析的文章,您可能会发现它很有用。

于 2012-10-01T12:00:35.763 回答
1

尝试更改您的基本方法以使用 BaseDataClass 并覆盖它。提供派生数据特定版本作为“新”方法(根据@Jon Skeet 的回答)

class Program
    {
        private static void Main(string[] args)
        {
            ConsumingDerivedClass x = new ConsumingDerivedClass();
            // Wrong DoWork is called - expected calling of DoWork(DerivedDataClass) but actually called DoWork(BaseDataClass) 
            x.DoWork(new DerivedDataClass());
            x.DoWork(new BaseDataClass());
            Console.ReadKey();
        }
    }

    public class ConsumingBaseClass
    {
        public virtual void DoWork(BaseDataClass instance)
        {
            Console.WriteLine("ConsumingBaseClass.DoWork(DerivedDataClass); Type of argument is '{0}'", instance.GetType());
        }
    }

    public class ConsumingDerivedClass : ConsumingBaseClass
    {
        public override void DoWork(BaseDataClass instance)
        {
            Console.WriteLine("ConsumingDerivedClass.DoWork(DerivedDataClass); Type of argument is '{0}'", instance.GetType());
            base.DoWork(instance);
            // Some additional logic 
        }

        public void DoWork(DerivedDataClass instance)
        {
            Console.WriteLine("ConsumingDerivedClass.DoWork(BaseDataClass); Type of argument is '{0}'", instance.GetType());
            DerivedDataClass derivedInstance = new DerivedDataClass();
            // Some logic based on what is in baseInstacne 
            derivedInstance.SomeProperty = "Value, got from some logic";

            base.DoWork(derivedInstance);
            // Some additional logic 
        }
    }

    public class BaseDataClass
    { }

    public class DerivedDataClass : BaseDataClass
    {
        public string SomeProperty { get; set; }
    } 
于 2012-10-01T12:07:06.313 回答