【问题标题】:Why does overridden auto-implemented property in derived class have a different value from virtual base class property in C#为什么派生类中重写的自动实现属性与 C# 中的虚拟基类属性具有不同的值
【发布时间】:2018-03-19 16:04:51
【问题描述】:

我有一个“基础”,它有一个名为“id”的virtual int 自动实现的属性。

class bbase
{
    public virtual int id { get; set; }

}

当我从这个类继承到“派生”类时,我得到:

class Derived : bbase
{
    public override int id
    {
        get
        {
            return base.id;
        }
        set
        {
            base.id = value;
        }
    }
}

在初始化基类和派生类并将值分配给基类属性后,如下所示:

bbase b2 = new bbase();
Derived d2 = new Derived();
b2.id = 6;

当我尝试从派生类输出值时,它输出“0”:

Console.WriteLine(d2.id);

我的困惑是,当我使用虚拟方法尝试相同的方法时,它可以正常工作。带有base.method() 的派生类方法可以正常工作。它返回基本方法中的任何内容,但为什么不返回自动实现的属性?

class bbase 
{
    public virtual void execute() { Console.WriteLine("base.execute2"); }
}

class Derived : bbase
{
     public override void execute()
     {
         base.execute();
     }
}

【问题讨论】:

  • b2 无论如何都不会连接到您的 d2 实例。您可以强制转换 b2 = (bbase)d2; 并查看它是否有效,但您正在创建两个完全不同的对象,它们包含的值彼此不相关。
  • 在 b2 = (bbase)d2 之后;现在两者都为零
  • b2 和 d2 不是同一个实例?为什么你会期望在一个中设置一个值会对另一个产生影响?当然,在那次演员之后两者都为零 - 你还没有设置 d2.id
  • 重写虚拟成员的期望效果是替换实现(如果有)。因此,如果您有List<bbase> 并在那里存储Derived 的实例,那么在调用虚拟成员时将调用后一种类型的实现。继承和覆盖都与 2 个不同的实例无关。
  • 方法是类的行为,它们没有值。但是属性是有值的。因此,基类和派生类的两个不同对象可能具有相同的行为,但它们的属性可能具有不同的值。

标签: c# inheritance properties overriding


【解决方案1】:

两者都是两个独立的对象。所以你看到的是预期的结果。

如果您重新编写代码以使变量b2d2 都指向Derived 类对象,则可以完成您尝试模拟的操作,如下所示:

Derived d2 = new Derived();
bbase b2 = d2;
b2.id = 6;

现在如果你这样做:

Console.WriteLine(d2.id); // prints 6

您将看到与上面设置的相同的值。

See DEMO here.

理想情况下,我认为您不应该像上述情况那样在属性 getter 和 setter 中以这种方式调用 base,因为您没有对 base 的值做任何特别的事情,而不是只使用默认的 @987654329 @ 和 set 派生如下:

class Derived : bbase
{ 
    public override int id
    {
        get;
        set;
    }
}

现在如果你写以下内容:

Derived d2 = new Derived();
bbase b2 = d2;
b2.id = 6;
Console.WriteLine("d2:"+d2.id);
Console.WriteLine("b2: "+b2.id);

它会输出:

d2: 6

b2: 6

请参阅working DEMO Fiddle 了解它。

【讨论】:

  • 这行得通,但我仍然有一点困惑,方法和属性显然都是以相同的方式实现的,但是属性需要强制转换,但方法却不需要方法和属性都来自不同的对象。为什么会这样?
  • @M.Asif 当您从子类类型变量转换为父类时,您不需要转换,但在其他情况下您需要(父类型变量到子类)
  • 在您的示例中,您两次都使用d2 进行打印
  • 感谢@Antry 的更正,更新了代码和小提琴演示
【解决方案2】:

b2d2 是不同的对象。你可以知道,因为你每个人都做了一次new

如果您创建了属性static,您会看到预期的结果。

【讨论】:

  • 但这些方法也源自不同的对象,但它们产生相同的结果。为什么属性不同?还是我没听懂?
  • @M.Asif 方法存在于基类和派生类中,就像属性一样。不同之处在于您为属性分配了一个值,并期望将其传递给另一个对象。你不是用这个方法做的。
  • 我们不是从派生类调用基类方法实现吗??类 bbase { public virtual void execute() { Console.WriteLine("base.execute2"); } } 类派生: bbase {public override void execute() { base.execute(); } }
  • @M.Asif 是的,并且该属性也在调用基本实现。区别在于价值。您的方法调用中不涉及实例值。
【解决方案3】:

我认为您在这里遗漏了一些基础知识。

您的bbase 类将实例级别 属性“id”定义为虚拟。这意味着它可以被覆盖:

class bbase
{
    public virtual int id { get; set; }
}

您的Derived 类覆盖了实例级别属性“id”:

class Derived : bbase
{
    public override int id
    {
        get
        {
            return base.id;
        }
        set
        {
            base.id = value;
        }
    }
}

这意味着Derived 的任何实例都以这种覆盖的方式处理“id”属性。

当你实例化你的对象时:

bbase b2 = new bbase();
Derived d2 = new Derived();

您正在为每个类创建一个实例。这些实例的属性有自己的值。继承不相关,因为它们是两个独立的实例。您对d2 所做的任何事情都不会反映在b2 中,因为它们是不同的。

【讨论】:

  • 当这两个类都具有不同的对象并具有虚拟方法时,这就是我要学习的内容,并支持为什么派生类方法能够输出基类方法实现而不是属性
  • @M.Asif 一个属性有一个值,一个方法就是一个动作。属性的因实例而异。
  • hm 属性带有值和方法只是类的行为似乎是合乎逻辑的
【解决方案4】:

其实b2d2是不同的对象。 所以如果你设置了b2.id = 6;,那么d2保持为0,只要你也设置了d2.id = 6;

在您的虚拟方法示例中,您正在返回(通过覆盖它)基方法 => base.execute();,这就是为什么即使您实例化了 d2 类也会得到基方法输出的原因。

【讨论】:

    【解决方案5】:

    如果您的代码如下所示:

    bbase b2 = new bbase();
    bbase d2 = new bbase();
    b2.id = 6;
    Console.WriteLine(d2.id);
    

    您希望结果不是 0 吗?是一样的区别。

    仅当您将派生类分配给基类的引用时,覆盖、隐藏和其他多态才有意义。

    Derived d2 = new Derived();
    d2.id = 6;
    bbase b2 = d2;
    Console.WriteLine(b2.id);
    

    这种分配在任何 OOP 语言中都经常发生。它在使用 OOP 点的 1/2 到 3/4 之间。

    【讨论】:

      猜你喜欢
      • 2011-11-04
      • 2022-12-11
      • 2011-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-21
      • 1970-01-01
      • 2012-09-01
      相关资源
      最近更新 更多