.net根据参数类型选择错误的方法来调用

时间:2012-10-01 11:55:42

标签: c# overloading derived-class

我有两个数据类: BaseDataClass DerivedDataClass ,它们派生自第一个。 我还有两个消费类: ConsumingBaseClass ConsumingDerivedClass ,它们派生自第一个。 在 ConsumingBaseClass 中,我有虚拟方法 DoWork ,它接受 DerivedDataClass < / strong>并做一些工作。

ConsumingDerivedClass 中,我对方法 DoWork 进行了覆盖,并且我还有 DoWork ,接受 BaseDataClass 。 当我尝试调用 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; } 
}

2 个答案:

答案 0 :(得分:7)

  

有没有人知道,为什么要调用错误的方法?

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

  

在ConsumingDerivedClass中,我有方法DoWork的覆盖,并且我对DoWork也有重载,它接受BaseDataClass。

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

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

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

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

基本上,请查看我brainteasers page上的第一个问题,以及第一个答案的详细信息。我也有article on overload resolution您可能会觉得有用。

答案 1 :(得分: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; }
    }