Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么不在构造函数中调用可重写的方法?_C#_Methods_Constructor_Overriding - Fatal编程技术网

C# 为什么不在构造函数中调用可重写的方法?

C# 为什么不在构造函数中调用可重写的方法?,c#,methods,constructor,overriding,C#,Methods,Constructor,Overriding,这是一个过于简化的示例,但我有一些实际代码在概念上做了相同的事情(尝试验证派生类的值“set”访问器方法),并且分析器给我“不要调用构造函数中的可重写方法”。我试图弄清楚是应该更改代码,还是忽略警告。我想不出任何理由应该听从这个警告 public abstract class SimpleUrl { protected string _url; public abstract string Url { get; set; } public SimpleUrl()

这是一个过于简化的示例,但我有一些实际代码在概念上做了相同的事情(尝试验证派生类的值“set”访问器方法),并且分析器给我“不要调用构造函数中的可重写方法”。我试图弄清楚是应该更改代码,还是忽略警告。我想不出任何理由应该听从这个警告

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

答案确实是,这可能会导致意外行为

代码中缺少的内容:

public class HttpUrl : SimpleUrl
{
    public HttpUrl()**:base()**
    { }
    public HttpUrl(string Url)**:base(Url)**
    {
        this.Url = Url;
    }
.........
}
你现在明白了吗? 你不能让构造函数暴露你的基。然后,在设置虚拟成员之前,base将执行其构造函数

正如T.S.所说(谢谢T.S.),在实例化派生类型时,将始终调用基构造函数。如果您像我在问题中所做的那样,在派生构造函数没有明确指定要使用哪个基构造函数的情况下,则使用无参数基构造函数

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

因此,这个问题的完整答案是:如果密封了派生类,则基类中声明的抽象或虚拟方法只能在基类中重写。因此,要生成干净的代码,您不需要在基本构造函数中运行这一行:

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();
        }
    }
}
或者,如果只密封可重写的方法(使其不再可被任何其他派生类重写),则不需要密封整个派生类


我想补充一点,构造函数中的调用和重写方法会使程序处于不一致的状态。如果您的方法抛出异常会发生什么?那么你的目标永远不会被构建。在构造函数中捕获这些异常不是一个好的实践

ctor()
{
    method(); //throws an exception
}
从Windows窗体可以学到的一个教训是,设计器具有从构造函数调用的InitializeComponents

public MyView: System.Windows.Forms.Form
{
   public MyView()
   {
      InitializeComponent();
   }
}
InitializeComponent由设计器生成。不要修改它 因为更改设计器属性时,更改将丢失。 InitializeComponent的目的只是让设计师将所有 它的代码用于设置所有属性,以及在需要时读取的位置 绘制设计器曲面,以便渲染相关的 组件设置


如果InitializeComponent是一个重写方法呢?然后您可以修改它,最后,如果您的更改错误并破坏基类上的逻辑,则整个表单可能处于不一致的状态

原因是子类可能在超类尚未初始化的方法中使用对象的属性,从而导致意外行为。Shoot。一分钟前,我发布了一个答案,这是错误的。所以我把它删掉了。以防万一有人注意到了。@EdwardNedHarvey我注意到了,并且仍然可以看到:-PBolding在源代码中不起作用-你只需要使用内联注释。我知道。这只是为了让某人注意到特定的部分-看起来像你那样:o)@T.S.谢谢你,我现在知道了。你的回答很有帮助,但不是一个完整的答案。我将为这个问题添加另一个答案。再次感谢您的帮助。@EdwardNedHarvey只是在谷歌上搜索“调用构造函数中的虚拟成员”之类的内容。为什么不这样做有不同的例子。要点-这不是犯罪,但如果你使用这种技术,你可能会得到扭曲的结果。事实上,在某些设计中,您可以接受这一点,因为使用对象继承的方式。我记得有一个应用程序充满了它,但从来没有出现过任何问题,因为它是经过设计完成的。@T.S.是的,在发布这个问题之前,我已经在谷歌上搜索过,并阅读了msdn。但答案从来都不清楚。我在问题中所写的代码似乎可以安全地使用,但我错了。现在我有了真正的答案。再次感谢你的帮助。
ctor()
{
    method(); //throws an exception
}
public MyView: System.Windows.Forms.Form
{
   public MyView()
   {
      InitializeComponent();
   }
}