views:

63

answers:

3

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?

+1  A: 
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...

Sunny
+2  A: 

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.

Dan Tao
+5  A: 

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"; } }
}
dtb
Thank you very much, this is what I needed to know. I'm going to assume it doesn't have to be a property though.
Nilbert
@Nilbert: You can't override fields -- that wouldn't make sense. So you have to use a property (or a method).
dtb
Oh ok, thanks very much. This will be marked the answer when the timer lets me do so.
Nilbert