1

最初のクラスから派生したBaseDataClassDerivedDataClassの 2 つのデータ クラスがあります。また、最初のクラスから派生したConsumingBaseClassConsumingDerivedClassの 2 つの Consuming クラスがあります。ConsumingBaseClassには、 DerivedDataClassを受け入れて何らかの作業を行う仮想メソッドDoWorkがあります。

ConsumingDerivedClassでは、メソッドDoWorkのオーバーライドがあり、また、 BaseDataClassを受け入れるDoWorkのオーバーロードがあります。DoWorkを呼び出そうとすると、 DerivedDataClassのインスタンスを渡して、 DoWork (DerivedDataClass)の代わりにDoWork (BaseDataClass)が呼び出されます。

なぜ間違ったメソッドが呼び出されるのか、誰にもわかりませんか?

次のコードは、問題を示しています。

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 に答える