为什么不在构造函数中调用可覆盖的方法?

Edw*_*vey 11 c# methods constructor overriding

这是一个过于简单的例子,但我有一些现实生活中的代码在概念上做同样的事情(试图验证派生类的"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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Edw*_*vey 5

正如TS所说(谢谢TS),在实例化派生类型时,将始终调用基础构造函数.如果你像我在问题中所做的那样,衍生构造函数没有明确指定要使用哪个基础构造函数,那么使用无参数基础构造函数.

public HttpUrl()           // : base() is implied.
Run Code Online (Sandbox Code Playgroud)

public HttpUrl(string Url) // : base() is still implied.  
                           // Parameterless. Not :base(Url)
Run Code Online (Sandbox Code Playgroud)

所以这个问题的完整答案是:如果你密封了派生类,那么在基类中声明的抽象或虚方法只能在基类中覆盖.因此,要创建干净的代码,不要在基础构造函数中运行此行:

this.Url = Url;   // Don't do this in the base constructor
Run Code Online (Sandbox Code Playgroud)

相反,你应该"密封"衍生类(或方法).如下:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您只是密封可覆盖的方法(使其不再被任何其他衍生类别覆盖),则不需要密封整个衍生类别.

public class HttpUrl : SimpleUrl
{
    // ...
    public override sealed string Url
    // ...
Run Code Online (Sandbox Code Playgroud)