Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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#_Oop_Inheritance_Polymorphism - Fatal编程技术网

C# 访问子类';来自基类的属性';建造师

C# 访问子类';来自基类的属性';建造师,c#,oop,inheritance,polymorphism,C#,Oop,Inheritance,Polymorphism,我发现了一些奇怪的东西,我没想到会起作用,实际上起作用了。我可以从基类构造函数访问子类“(常量)属性: public abstract class Parent { public Parent() { var constName = ConstName; // <-- surprisingly, this works var randomName = RandomName; // <-- surprisingly, t

我发现了一些奇怪的东西,我没想到会起作用,实际上起作用了。我可以从基类构造函数访问子类“(常量)属性:

public abstract class Parent {

  public Parent() {
    var constName = ConstName;            // <-- surprisingly, this works  
    var randomName = RandomName;          // <-- surprisingly, this works  
  }

  public abstract string ConstName { get; }

  public abstract string RandomName { get; }

}


public class Child : Parent {

  public override string ConstName { get { return "Mike"; } }

  public override string RandomName { get { return new Random().Next().ToString(); } }

}
公共抽象类父类{
公共家长(){

var constName=constName;//Parent有一个抽象属性Parent.Name。由于单词abstract,您承诺Parent的(子类)实例将实现属性Name。如果它们不实现,则无法创建它的对象

请注意,我说的是:不能创建实例。如果子类没有实现属性名,则该类可以存在,但不能实例化它

类父级不实现属性名,因此不能实例化父级

然而,类Child实现了名称,因此您可以实例化它,并且因为您承诺类Parent的每个对象(=实例化)都有一个属性名称,所以您可以确保,尽管您所知道的只是它是父对象,但您也知道它有一个名称

这是亚型多态性的基本原理


这可能是您想要子类化的主要原因。

您可以访问子类型的抽象/虚拟成员。属性getter最终是方法

但是

正如您所说,子类构造函数尚未执行。因此,它可能有副作用。这就是为什么您会收到FxCop的警告

public abstract class Parent
{
  public Parent() 
  {
    // NullReferenceException here:
    var nameLength = Name.Length;
  }

  public abstract string Name { get; }

}

public class Child : Parent 
{
  private string name;

  public Child()
  {
    name = "My Name";
  }

  public override string Name { get { return name; } }
}
更糟糕的是:

public class Child : Parent 
{
  private string name;

  public Child()
  {
    name = "My Name";
  }

  public override string Name
  { 
    get 
    { 
      // NullReferenceException here.
      // You didn't expect that this code is executed before
      // the constructor was, did you?
      return name.Substring(0, name.Length - 1);
    } 
  }
}

因此,不建议这样做。

您在父对象中有Name属性!因此从技术上讲,这是合法的且正确的。@Nikita是的,但子对象尚未构造。请阅读我问题中的初始化顺序。属性编译为方法Get和Set,因此它就像您使用字符串return调用方法一样。它与const无关,它将将getter视为method.Run Code Analysis(FxCop),它将报告有意义的警告Yes。您指的是编译时契约,因此可以确定是否存在子属性。但这里的要点是,您是在子属性(完全)之前执行此操作的构造。这就是我不明白的?再看一遍,你的答案基本上解释(非常好)多态性的总体思想。但不是构造顺序,这是这个问题的核心。由于抽象函数,父类的构造函数知道要构造的对象是父类的子类。虽然子类的构造尚未完成,但子类已经完全存在。在每个类中构造函数,即使没有基类,也必须小心初始化对象项的顺序。可以调用方法和属性,但要确保它们只使用已初始化的项。对。因此,我对这种行为感到惊讶是正确的,因为它没有意义。我想这不容易o防止这种行为,因此编译器团队允许它,但创建了FxCop警告来告诉您这是一个“非常糟糕的想法”。基本上,这会导致非确定性的输出!我想我的问题可以这样想:仅仅因为编译了某个东西,并不意味着它“正确”。有一些奇怪的边缘情况是编译器无法教给你的。构造函数中有很多暗魔法:)。甚至可能有一些情况下它是有用的。你可以有属性,比如你的属性,它们返回常量或纯逻辑,不访问对象状态。你只需要知道你在做什么。非常正确,它在s中可能有用一些案例——对我来说,这就是为什么我偶然发现了这个问题。但我宁愿谨慎一点,因为这不是一个简单的问题……想象一下初级团队成员使用/滥用编译器边缘案例:-(。