[英]Why do not call overridable methods in constructors?
這是一個過於簡單的例子,但我有一些現實生活中的代碼在概念上做同樣的事情(試圖驗證派生類的“set”訪問器方法的值),並且Analyzer給了我“不要在構造函數中調用可覆蓋的方法”。 我試圖找出是否應該更改我的代碼,或忽略警告。 我想不出任何理由我應該注意這個警告。
public abstract class SimpleUrl
{
protected string _url;
public abstract string Url { get; set; }
public SimpleUrl()
{ }
public SimpleUrl(string Url)
{
this.Url = Url;
}
}
public class HttpUrl : SimpleUrl
{
public HttpUrl()
{ }
public HttpUrl(string Url)
{
this.Url = Url;
}
public override string Url
{
get
{
return this._url;
}
set
{
if (value.StartsWith("http://"))
this._url = value;
else
throw new ArgumentException();
}
}
}
正如TS所說(謝謝TS),在實例化派生類型時,將始終調用基礎構造函數。 如果你像我在問題中所做的那樣,衍生構造函數沒有明確指定要使用哪個基礎構造函數,那么使用無參數基礎構造函數。
public HttpUrl() // : base() is implied.
和
public HttpUrl(string Url) // : base() is still implied.
// Parameterless. Not :base(Url)
所以這個問題的完整答案是:如果你密封了派生類,那么在基類中聲明的抽象或虛方法只能在基類中覆蓋 。 因此,要創建干凈的代碼,不要在基礎構造函數中運行此行:
this.Url = Url; // Don't do this in the base constructor
相反,你應該“密封”衍生類(或方法)。 如下:
public abstract class SimpleUrl
{
protected string _url;
public abstract string Url { get; set; }
// Optionally declare base constructors that do *not* call Url.set
// Not sure why these constructors are optional in the base, but
// required in the derivative classes. But they are.
public SimpleUrl()
{ }
}
public sealed class HttpUrl : SimpleUrl
{
public HttpUrl() // Not sure why this is required, but it is.
{ }
public HttpUrl(string Url)
{
// Since HttpUrl is sealed, the Url set accessor is no longer
// overridable, which makes the following line safe.
this.Url = Url;
}
public override string Url
{
get
{
return this._url;
}
set
{
if (value.StartsWith("http://"))
this._url = value;
else
throw new ArgumentException();
}
}
}
或者,如果您只是密封可覆蓋的方法(使其不再被任何其他衍生類別覆蓋),則不需要密封整個衍生類別。
public class HttpUrl : SimpleUrl
{
// ...
public override sealed string Url
// ...
答案確實是,這可能會導致意外行為。
http://msdn.microsoft.com/en-us/library/ms182331.aspx
您在代碼中遺漏的東西:
public class HttpUrl : SimpleUrl
{
public HttpUrl()**:base()**
{ }
public HttpUrl(string Url)**:base(Url)**
{
this.Url = Url;
}
.........
}
你現在看到了嗎? 你不能沒有構造函數你的基礎暴露。 然后,base將在您設置虛擬成員之前執行其構造函數。
我想補充說,構造函數中的調用和覆蓋方法可能會使程序處於不一致狀態。 如果您的方法拋出異常會發生什么? 那么你的對象永遠不會被構造出來。 在構造函數中捕獲這些異常並不是一個好習慣。
ctor()
{
method(); //throws an exception
}
您可以從Windows窗體中學到的一個教訓是,設計器具有從構造函數調用的InitializeComponents。
public MyView: System.Windows.Forms.Form
{
public MyView()
{
InitializeComponent();
}
}
InitializeComponent由設計者生成。 不要修改它,因為更改設計器屬性時更改將丟失。 InitializeComponent的目的僅僅是讓設計者將所有代碼設置為設置所有屬性,並在繪制設計器表面時將其讀取,以便呈現相關的組件設置
如果InitializeComponent是覆蓋方法怎么辦? 然后你可以修改它,最后,如果你的更改是錯誤的,整個表單可能處於不一致的狀態並打破基類的邏輯
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.