i have a parent class coming from a library i don't control, and i'm trying to create a child class that overrides a public property in that class. i found that the answer is to use the new
keyword, but i'm confused about the behavior. here is an example:
public class A {
public string Q { get; private set; }
public A(string q) {
Q = q;
}
}
public class B : A {
public new string Q { get; private set; }
public B(string q) : base("no") {
Q = q;
}
}
...
[Fact]
public void Test() {
var a = new A("a");
var b = new B("b");
A c = new B("c");
throw new Exception($"{a.Q} {b.Q} {c.Q}");
}
this results in:
System.Exception: a b no
but i want:
System.Exception: a b c
the code i'm calling accepts an A
, so i pass it an instance of my child class B
that has a customized property getter, but the library code is still using the getter from A
, which results in incorrect behavior.
is this just not possible? i tried the same thing with methods instead of properties and it also didn't work. i'm so confused ;-;
the point of new
is, that it only hides the overriden member. That member still exists with the exact same name, so when you're accessing your instance via a base-class reference, the base-class-member is called.
An easier way of thinking is, that new
just introduces a completely new member, e.g.:
class A
{
public string MyString { get; set; }
}
Now instead of overriding MyString
, the new
-keyword just creates a second property, which has no relation to MyString
from class A
. So what the compiler more or less does, is creating a second member (e.g. AnotherString
) in your derived class with another name and replace all occurences of B.MyString
in the codebase by that new property:
class B : A
{
// actually this property has the same name, however it has nothing to do with MyString from class A
public string AnotherString { get; set; }
}
Now all calls to B.MyString
are replaced by B.AnotherString
. However your library surely has no clue B
even exists. There will allways ever be only refereces to your base-class. So the compiler won't replace these properties. Effectivly you have two properties, not just one.
This is just a simplification, the compiler won't really rename your property, but it's easier to get the idea.
So when your library-provider didn't implement any means of extensibility - which is by making the member abstract
or virtual
, there is no way of extending it.