为什么不叫在构造函数中重写方法? [英] Why do not call overridable methods in constructors?

查看:148
本文介绍了为什么不叫在构造函数中重写方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个过于简单的例子,但我有一些现实生活中的代码,在概念上做同样的事情(试图验证值设置衍生类的存取方法),并分析给了我不要叫在重写方法构造函数。我想弄清楚,如果我要改变我的代码,或者忽略警告。我想不出任何理由,我应该听从警告。

 公共抽象类SimpleUrl 
{
保护字符串_url;
公共抽象的字符串URL {搞定;组; }
公共SimpleUrl()
{}
公共SimpleUrl(字符串URL)
{
this.Url =网址;
}
}

公共类HttpUrl:SimpleUrl
{
公共HttpUrl()
{}
公共HttpUrl(串URL)
{
this.Url = URL;
}
公众覆盖字符串URL
{
得到
{
返回this._url;
}

{
如果(value.StartsWith(HTTP://))
this._url =价值;
,否则
抛出新的ArgumentException();
}
}
}


解决方案

作为TS说(谢谢T.S.),基构造函数总是被调用,实例化派生类型时。如果你这样做,因为我的问题,那里的衍生构造函数不的明确的指定使用哪个基构造函数,则使用参数的基础构造。


$ B $做b

 公共HttpUrl()//:基地()是隐含的。 

 公共HttpUrl(字符串URL)//:基地()仍然暗示。 
//无参数。不:基地(URL)



所以,完整的答案是:抽象或虚拟方法声明在基类只的重写的基类,如果你的密封的衍生类。因此,为了使简洁的代码,你不跑在基础构造这一行:

  this.Url =网址; //不要这样做在基本构造

您而应该封的衍生类(或方法)。具体如下:

 公共抽象类SimpleUrl 
{
保护字符串_url;
公共抽象的字符串URL {搞定;组; }
//可选声明的基础构造那些*不*调用Url.set
//不知道为什么这些构造的基础是可选的,但
//在衍生类必需的。但他们。
公共SimpleUrl()
{}
}

公共密封类HttpUrl:SimpleUrl
{
公共HttpUrl()//不知道为什么这是必需的,但它是。
{}
公共HttpUrl(字符串URL)
{
//由于HttpUrl是密封的,URL中设置访问不再
//重写,这使得以下行的安全。
this.Url =网址;
}
公众覆盖字符串URL
{
得到
{
返回this._url;
}

{
如果(value.StartsWith(HTTP://))
this._url =价值;
,否则
抛出新的ArgumentException();
}
}
}



另外,你不需要密封整个衍生类,如果你只是封重写的方法(通过任何进一步的衍生类使它不再重写)

 公共类HttpUrl:SimpleUrl 
{
// ...
公众覆盖密封字符串URL
// ...


This is an oversimplified example, but I have some real-life code that conceptually does the same thing (trying to validate values "set" accessor methods of derivative classes), and the Analyzer gives me "Do not call overridable methods in constructors." I'm trying to figure out if I should change my code, or ignore the warning. I can't think of any reason I should heed the warning.

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();
        }
    }
}

解决方案

As T.S. said (thank you T.S.), the base constructor will always be called, when instantiating the derived type. If you do as I did in the question, where the derivative constructor does not explicitly specify which base constructor to use, then the parameterless base constructor is used.

public HttpUrl()           // : base() is implied.

And

public HttpUrl(string Url) // : base() is still implied.  
                           // Parameterless. Not :base(Url)

So the complete answer to this question is: The abstract or virtual methods declared in the base class are only overridable in the base class, if you sealed the derivative class. So to make clean code, you don't run this line in the base constructor:

this.Url = Url;   // Don't do this in the base constructor

You instead, should "sealed" the derivative class (or method). As follows:

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();
        }
    }
}

Alternatively, you don't need to seal the entire derivative class, if you just seal the overridable method (making it no longer overridable by any further derivative classes)

public class HttpUrl : SimpleUrl
{
    // ...
    public override sealed string Url
    // ...

这篇关于为什么不叫在构造函数中重写方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆