Why is it that when I set a shadowed field (declared using new keyword) in a base class constructor, the field that was shadowed gets set but not the field that is shadowing?
I thought that this.GetType() referred to the outermost class all the way down into base class calls including the constructor. I also thought that shadowing made the shadowed field not accessible.
In my quick watch I can see two fields, the shadowed one that got set and the shadowing one (of the subclass) that is still not initialized.
I fixed it by explicitly setting the shadowing field in the subclass constructor after it calls the base class constructor, but I'd still like to know why it acts this way. .Net Fiddle
using System;
public class Program
{
public static void Main()
{
SubClass subClass = new SubClass(2);
Console.WriteLine(subClass.MyField);
}
}
public class BaseClass
{
public BaseClass(int value)
{
MyField = value; // This doesn't point to SubClass.MyField
}
public int MyField;
}
public class SubClass : BaseClass
{
public SubClass(int value):base(value)
{
}
public new int MyField = 4;
}
Update
After reviewing the answers, I see I didn't ask what I wanted to know in the most direct way. Sorry for any inconvenience. Here's what I really want to know:
I do understand shadowing. I don't agree with it. I don't think it should be allowed for fields (as long as overridable fields were made a language feature). I don't see the point in shadowing fields and having the shadowed field hanging around. I do however see the point in overridable fields and I don't understand why that language feature doesn't exist when it exists for properties and methods. So, why have shadowing on fields? Why is there not overriding on fields?
We have
I also thought that shadowing made the shadowed field not accessible.
Followed by
I do understand shadowing.
I'm not entirely sure that you do. You've already expressed one false belief about shadowing; how do we know there aren't more?
I don't agree with it.
Your opinion is noted. I note that you are not required to use the feature if you don't like it.
I don't think it should be allowed for fields (as long as overridable fields were made a language feature).
Noted.
I do however see the point in overridable fields and I don't understand why that language feature doesn't exist when it exists for properties and methods.
Fields should be private implementation details of classes. If they are, then there is no accessible name to shadow or override, so the problem is moot. A feature that we would want no one to use is a bad feature.
So, why have shadowing on fields?
Suppose there is a protected field in a derived class. Now consider the brittle base class problem. Work through a number of such scenarios; you're critiquing a language design choice, so think like the language designers think. What do you conclude from your investigation into typical brittle base class scenarios?
Why is there not overriding on fields?
Because (1) we have no mechanism for overriding fields; methods have vtables but there is no vtable mechanism for fields. And (2) fields should be private implementation details of classes, and therefore there is never a need to override them. If you want to override a field, make a property that wraps it and override that. The code change is tiny to go from a field to a virtual property.
Fields should be in the mechanism domain of the class; properties are in the business domain. Specialization of behaviour belongs in the business domain.
public class BaseClass { public BaseClass(int value) { MyField = value; // This doesn't point to SubClass.MyField } public int MyField; }
The base class doesn't know about its derived types. MyField = value does exactly what it says it's doing: it assigns MyField with value.
public class SubClass : BaseClass { public SubClass(int value):base(value) { } public new int MyField = 4; }
Are you expecting the value 4 to propagate to the base type? Your question is quite hard to answer, because it's not exactly clear what your definition of "intuitive" and expectations are.... and your example code is very poor OOP design.
There aren't lots of valid reasons to ever expose a public field, base class or not.
Let me rephrase your example:
public abstract class BaseClass
{
protected BaseClass(int value)
{
_value = value;
}
private int _value;
public virtual int Value { get { return _value; } set { _value = value; } }
}
public class SubClass : BaseClass
{
public SubClass(int value) : base(value)
{
}
public new int Value { get; set; } // hides base class member
}
Now. SubClass.Value is its own thing - if you want to access the value that was passed down the constructor, you need to do so via the base class.
The base class member doesn't "cease to exist", it's only hidden, or shadowed, by a new member in a derived type, that just so happens to have the same identifier:
var foo = new SubClass(42);
Console.WriteLine(foo.Value);
Console.WriteLine(((BaseClass)foo).Value);
Console.ReadKey();
This code outputs 0, then 42 - because when foo.Value gets accessed the SubClass says "hey base class, let me handle this - I have my own definition of Value, and this call mine to pick up." ...and returns 0 because, well, it's never actually assigned; the 42 is only visible via the base class.
That is what member shadowing does.
And it works the same even without the new keyword - the new keyword merely suppresses a compiler warning that says "you're hiding a base class member here, are you really totally completely sure you intend to be doing this?" - because in a normal world, that typically isn't what you would want to be doing.
Now, notice I made the Value property virtual. What happens if you override it instead?
public class SubClass : BaseClass
{
public SubClass(int value)
: base(value)
{
}
public override int Value { get; set; }
}
The little console program above (a few snippets up) will now output 0 and 0 - because the subclass' Value overrides the base class member, effectively telling C# to resolve member calls to the derived type. So to output the 42 you're passing in, because you're overriding the member, you become responsible for how it works - the _value private field in the base class still says 42, but the Value property being overridden, the field is left unused.
So you assign it in your derived type's constructor (here sealing the class to avoid a virtual member call in the constructor):
public sealed class SubClass : BaseClass
{
public SubClass(int value)
: base(0)
{
Value = value;
}
public override int Value { get; set; }
}
So, here the derived type is passing 0 to the base class, and overriding the member. What does the little snippet output for 42 now?
static void Main(string[] args)
{
var foo = new SubClass(42);
Console.WriteLine(foo.Value);
Console.WriteLine(((BaseClass)foo).Value);
Console.ReadKey();
}
it will output 42 for both the derived and the downcasted calls, because the type cast is now redundant, since the virtual member is overridden.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With