I'm brushing up on my C# after many years. I'm very rusty so this may be me not the compiler.
Virtual function calls seem to stop working as I'd expect with generics. Here's the code:
namespace ConsoleApp1 {
public abstract class Root {
// force me to implenent ToString() in subclasses
public abstract new string ToString();
}
public class Mammal : Root {
string m;
public Mammal(string mIn) { m = mIn; }
public override string ToString() => m;
}
// allow me to give a mammal a name:
public class NamedMammal : Root {
Mammal m; string name;
public NamedMammal(Mammal mIn, string nameIn) {
m = mIn; name = nameIn;
}
public override string ToString() =>
$"({m.ToString()} has name {name})";
}
// but I may want to name many things, so make
//the thing being named generic:
public class NamedThing<Tthing> : Root {
Tthing thing; string name;
public NamedThing(Tthing thingIn, string nameIn) {
thing = thingIn; name = nameIn;
}
public override string ToString() =>
$"({thing.ToString()} has name {name})";
}
// I can name tractors or planets if I want to now
class Program {
static void Main() {
Mammal c = new Mammal("cow");
NamedMammal nm = new NamedMammal(c, "daisy");
Console.WriteLine(nm.ToString());
// output, as expected:
// (cow has name daisy)
Mammal f = new Mammal("fox");
NamedThing<Mammal> nt =
new NamedThing<Mammal>(f, "freddie");
Console.WriteLine(nt.ToString());
// not what I expected:
// (ConsoleApp1.Mammal has name freddie)
}
}
}
It's clearly not lost the type because it outputting it as 'ConsoleApp1.Mammal' so it knows it's a mammal but it doesn't seem to be calling ToString() on it as I'd expect. I'd guess it's calling the base-most object ToString() instead of the most derived.
Is this as designed, if so could someone give me some pointers, and perhaps an idea of how to deal with this because I don't want to handwrite buckets of boilerplate.