简体   繁体   English

C#继承的成员变量行为异常

[英]C# Inherited member variables behaving undexpectedly

If I have a class like this: 如果我有这样的课程:

class A {
    public string fe = "A";
}

And a class that inherits from it like so: 并从中继承的类如下:

class B : A {
    public string fe = "B";
}

Visual C# will tell me that B.fe hides A.fe so I should use the new keyword. Visual C#会告诉我B.fe隐藏了A.fe,因此我应该使用new关键字。 So I change class B to look like: 因此,我将B类更改为:

class B : A {
    public new string fe = "B";
}

And then I have a function that takes an A (but, by virtue of inheritance, will also take a B) like this: 然后,我有一个采用A的函数(但由于继承,也将采用B):

class D {
    public static void blah(A anAObject) {
        Console.Writeline(A.fe);
    }
}

Even when I pass it an instance of a B object, which it will take without question, it will print "A"! 即使我将其传递给B对象的实例,也毫无疑问,它将打印“ A”! Why is this, and how can I make it work how I want without setting the variable in the constructor? 为什么会这样,又如何在不构造函数中设置变量的情况下使它按我的意愿工作呢?

That's the difference between override and new . 那就是overridenew之间的区别。 new defines a member which happens to have the same name as a member in the base class. new定义一个成员,该成员恰好与基类中的成员具有相同的名称。 It doesn't override that member. 它不会覆盖该成员。 So if you have a method that expects an A instance, it will take the value of A.fe and not the member in the derived class with the same name. 因此,如果您有一个期望A实例的方法,它将采用A.fe的值,而不是派生类中具有相同名称的成员。

Use a property with override instead: 使用带有override的属性:

class A {
    public virtual string fe { get { return "A"; } }
}

class B : A {
    public override string fe { get { return "B"; } }
}

If you want your fe member to be overridable by derived classes without having to use the new keyword (which is why you're seeing the behavior you're seeing), just declare it virtual in the base class. 如果您希望fe成员可以被派生类覆盖而不必使用new关键字(这就是为什么您看到自己所看到的行为的原因),只需在基类中将其声明为virtual Then your code would look like this: 然后您的代码将如下所示:

public class A
{
    public virtual string fe
    {
        get { return "A"; }
    }
}

public class B
{
    public override string fe
    {
        get { return "B"; }
    }
}

Notice that this required making fe a property , since member fields cannot be declared virtual . 请注意,这需要使fe成为属性 ,因为不能将成员字段声明为virtual

The explanation for why you're not getting the behavior you want is that the new keyword only overrides an inherited member in the event that a variable is declared as the derived class at compile time. 为何无法获得所需行为的原因是,如果在编译时将变量声明为派生类,则new关键字仅覆盖继承的成员。 If it's declared as the base class at compile time (as anAObject is in your blah method), it goes with the base class version (this is what differentiates new from override ). 如果在编译时将其声明为基类(因为blah方法中包含anAObject ),那么它将与基类版本一起使用(这是newoverride区别)。

Now, you also could modify your blah method to cast its input to a B , thereby accessing your new fe : 现在,您还可以修改blah方法以将其输入转换为B ,从而访问new fe

public static void blah(A anAObject) {
    var aBObject = anAObject as B;
    if (aBObject != null)
        Console.WriteLine(aBObject.fe); // would print "B"
    else
        Console.WriteLine(anAObject.fe); // would print "A"
}

But I would not recommend this. 但是我不建议这样做。

class A {

public virtual string fe { get { return "A"; } set {} }

}

class B {
 public override string fe { get { return "B"; } set {} }
}

is what you need... 这就是你需要的...

AFAIK in the D.blah() the object is getting cast of type A & since the base value is not marked with the virtual keyword, it would behave as A & not as B even if the type is B ... AFAIK在D.blah()对象是越来越类型的铸造A &由于基值不与标记virtual关键字,这将表现为A &不如B即使类型是B ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM