这是一个过于简单的例子,但我有一些现实生活中的代码在概念上做同样的事情(尝试验证衍生类的值“设置”访问器方法),并且分析器给了我“不要调用可覆盖的方法构造函数“。我试图找出是否应该更改我的代码,或忽略警告。我想不出任何理由我应该注意这个警告。
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();
}
}
}
答案 0 :(得分:5)
作为T.S.说(谢谢T.S.),在实例化派生类型时,将始终调用基础构造函数。如果你像我在问题中所做的那样,衍生构造函数不显式地指定要使用哪个基础构造函数,那么使用无参数基础构造函数。
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
// ...
答案 1 :(得分:4)
答案实际上是,这可能导致意外行为。
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将在您设置虚拟成员之前执行其构造函数。
答案 2 :(得分:0)
我想补充一点,构造函数中的调用和覆盖方法会使程序处于不一致状态。如果您的方法抛出异常会发生什么?那么你的对象永远不会被构造出来。在构造函数中捕获这些异常并不是一个好习惯。
ctor()
{
method(); //throws an exception
}
您可以从Windows窗体中学到的一个教训是,设计器具有从构造函数调用的InitializeComponents。
public MyView: System.Windows.Forms.Form
{
public MyView()
{
InitializeComponent();
}
}
InitializeComponent由设计者生成。不要修改它 因为更改设计器属性时更改将丢失。 InitializeComponent的目的仅仅是让设计师放置所有 它的代码设置所有属性,以及它何时可以读取 绘制设计器表面,以呈现相关的 组件设置
如果InitializeComponent是覆盖方法怎么办?然后你可以修改它,最后,如果你的更改是错误的,整个表单可能处于不一致的状态并打破基类的逻辑