简体   繁体   中英

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. So I change class B to look like:

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:

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"! 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 . new defines a member which happens to have the same name as a member in the base class. 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.

Use a property with override instead:

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. 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 .

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. 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 ).

Now, you also could modify your blah method to cast its input to a B , thereby accessing your 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 ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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