2011-01-07 3 views
4

私は抽象クラスとDerivedクラスを持っています。抽象クラスはMessageという抽象プロパティを定義します。派生クラスでは、プロパティはabstractプロパティをオーバーライドすることによって実装されます。派生クラスのコンストラクタは文字列引数をとり、それをMessageプロパティに割り当てます。 Resharperでは、この割り当てによって「コンストラクターでの仮想メンバー呼び出し」という警告が表示されます。プロパティに値を代入するときのコンストラクタ内の仮想メンバー呼び出し

AbstractClassは、この定義があります。

public abstract class AbstractClass { 
    public abstract string Message { get; set; } 

    protected AbstractClass() {} 

    public abstract void PrintMessage(); 
} 

を、次のようDerivedClassがある:

using System; 

public class DerivedClass : AbstractClass { 
    private string _message; 

    public override string Message { 
     get { return _message; } 
     set { _message = value; } 
    } 

    public DerivedClass(string message) { 
     Message = message; // Warning: Virtual member call in a constructor 
    } 

    public DerivedClass() : this("Default DerivedClass message") {} 

    public override void PrintMessage() { 
     Console.WriteLine("DerivedClass PrintMessage(): " + Message); 
    } 
} 

私はこの警告に関するいくつかの他の質問を見つけたが、それらの状況で実際の呼び出しがあります方法に。たとえば、this questionでは、Matt Howels氏の回答にはいくつかのサンプルコードが含まれています。私はここで簡単に参照するためにそれを繰り返します。

class Parent { 
    public Parent() { 
     DoSomething(); 
    } 
    protected virtual void DoSomething() {}; 
} 

class Child : Parent { 
    private string foo; 
    public Child() { foo = "HELLO"; } 
    protected override void DoSomething() { 
     Console.WriteLine(foo.ToLower()); 
    } 
} 

マットは、警告が表示されますどのようなエラーには説明しませんが、私はそれが親のコンストラクタ内のdoSomethingの呼び出しになりますと仮定しています。この例では、仮想メンバーが呼び出されることが何を意味するのかを理解しています。メンバー呼び出しは、仮想メソッドのみが存在する基本クラスで発生します。

しかし私の状況では、なぜMessageに値を割り当てると仮想メンバーを呼び出すのかわかりません。 Messageプロパティの呼び出しと実装の両方が派生クラスで定義されています。

私の派生クラスsealedを作成することでエラーを取り除くことはできますが、この状況が警告になっている理由を理解したいと思います。ブレットの答えに基づいて

更新 は、私は最終的には、例外が発生しますDerivedClass由来ChildClassを作成するために私のベストを尽くしました。これは私が思い付いたものです:

using System; 

public class ChildClass : DerivedClass { 
    private readonly string _foo; 

    public ChildClass() : base("Default ChildClass Message") { 
     _foo = "ChildClass foo"; 
    } 

    public override string Message { 
     get { return base.Message; } 
     set { 
      base.Message = value; 
      Console.WriteLine(_foo.ToUpper() + " received " + value); 
     } 
    } 
} 

オフもちろん、メッセージセッターで_fooを使用するために少し愚かだが、ポイントは、ReSharperのは、このクラスに何かを見ていないということです。

しかし、もし、あなたがこのようなプログラムでChildClassを使用しよう:

internal class Program { 
    private static void Main() { 
     var childClass = new ChildClass(); 
     childClass.PrintMessage(); 
    } 
} 

ChildClassオブジェクトを作成するときは、とNullReferenceExceptionを取得します。 ChildClassのを使用しようとすると例外がスローされます。_fooはまだ初期化されていません。

答えて

6

あなたのメッセージプロパティはclass ChildClass : DerivedClassで上書きすることができますので、それはだ - それはDerivedClassにCTORからChildClassにメッセージ内のコードを呼び出すことも可能だし、あなたのChildClassインスタンスが初期化さいっぱいではないかもしれない、その時点で。

あなたのDerivedClassを封印することが問題を解決する理由です。これは継承できません。

+0

これは奇妙です。なぜ、それがDerivedClassで仮想でないとき、ChildClassがMessageプロパティをオーバーライドすることができますか?暗黙的にオーバーライドされていますか? – comecme

+1

実装をオーバーライドすると、仮想メンバーであるという事実は変更されません。あ、はい。 – Brett

+2

*メソッドをオーバーライドしたときに*メソッド*を 'sealed'としてマークすることもできます。つまり、誰もそれを子孫クラスでオーバーライドできないため、実質的に仮想ではありません。それも同様にエラーを削除する必要があります。 –

関連する問題