2011-01-07 54 views
4

我有一個Abstract類和一個Derived類。抽象類定義了一個名爲Message的抽象屬性。在派生類中,通過重寫抽象屬性來實現該屬性。派生類的構造函數接受一個字符串參數並將其分配給它的Message屬性。在Resharper中,此分配會導致警告「構造函數中的虛擬成員調用」。向屬性賦值時在構造函數中調用虛擬成員

的抽象類有這樣的定義:

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來擺脫錯誤,但我想了解爲什麼這種情況會導致警告。

更新 基於Brett的答案,我盡我所能去創建,這將最終導致異常的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.ToUpper(),因爲_foo尚未初始化,將拋出異常。

回答

6

這是因爲你的Message屬性可以通過class ChildClass : DerivedClass被覆蓋 - 在這一點有可能在留言上ChildClass從構造函數中調用DerivedClass代碼,您ChildClass實例可能不完全初始化。

這就是爲什麼讓你的密碼DerivedClass解決了問題 - 它不能被繼承。

+0

這很奇怪。爲什麼在DerivedClass中它不是虛擬的時候,ChildClass會覆蓋Message屬性?重寫是否隱含虛擬? – comecme 2011-01-07 13:20:20

相關問題