It's not possible to inherit from a C# struct. It's not obvious to me why this is:
I wonder if this is a technical limitation in the CLR, or something that the C# compiler stops you from doing?
Edit: Value types can't have virtual methods, and I realise this limitation rules out most scenarios in which you'd want to use inheritance. That still leaves inheritance-as-aggregation, though. Imagine a Shape
struct with a Colour
field: I can write code that accepts any struct derived from Shape
, and access its Colour
field, even if I can never write a virtual Shape.Draw
method.
I can think of one scenario that would get broken by non-sealed value types. Value types are supposed to implement Equals
and GetHashCode
correctly; even though these two methods on System.Object
are virtual, they get called non-virtually on value types. Even if value types weren't sealed, someone writing a struct derived from another one couldn't write their own implementation of these two methods and expect to have them called correctly.
I should point out that I'm not suggesting I should be able to inherit from structs in my own code. What I am trying to do, though, is to guess why this particular code smell is forbidden by .NET.
Edit 2: I just spotted this very similar question, the answer to which is effectively "because then arrays of value types wouldn't work".
The reason is that most inheritance techniques relate to runtime polymorphism (virtual functions) and those don’t work on value types: for runtime polymorphism to have any meaning, objects need to be treated as references – this isn’t specific to .NET either, it’s simply a technical detail of how virtual functions are implemented.
Value types form an exception to .NET’s rule, precisely to allow lightweight objects that don’t require indirection via references. So runtime polymorphism doesn’t work for them and most aspects of inheritance become meaningless.
(There’s an exception: a value type object can be boxed, which allows for virtual methods inherited from System.Object
to be called.)
To address one of your points:
- You could cast from a derived struct to the base, since they would overlap the same memory.
No, this would not be possible – casting a value type would copy its value. We’re not dealing with references here, so no overlap in memory. Casting a value type to its base type is therefore meaningless (again, unless we’re talking about conversion to object
which actually performs boxing under the hood, and also operates on a copy of the value).
Still not clear? Let’s look at an example.
Let’s say we’ve got the hypothetical struct Shape
and, inheriting from it, the struct Circle
. Shape
defines a virtual Draw
method (which accepts a Graphics
object). Now, let’s say we want to draw a shape on a canvas. This, of course, works perfectly well:
var circle = new Circle(new Point(10, 10), 20); circle.Draw(e.Graphics); // e.Graphics = graphics object of our form.
– But here we don’t actually use inheritance at all. To make use of inheritance, imagine instead the following DrawObject
helper method:
void DrawObject(Shape shape, Graphics g) { // Do some preparation on g. shape.Draw(g); }
And we call it elsewhere with a Circle
:
var circle = new Circle(new Point(10, 10), 20); DrawObject(circle, e.Graphics);
– And, ka-blam – this code doesn’t draw a circle. Why? Because when we pass the circle to the DrawObject
method, we do two things:
shape
object is really no longer a Circle
– neither the original one nor a copy. Instead, its Circle
portion was “sliced” away during copying and only the Shape
portion remains. shape.Draw
now calls the Draw
method of Shape
, not of Circle
.In C++, you can actually cause this behaviour. For that reason, OOP in C++ only works on pointers and references, not on value types directly. And for that same reason, .NET only allows inheritance of reference types because you couldn’t use it for value types anyway.
Notice that the above code does work in .NET if Shape
is an interface. In other words, a reference type. Now the situation is different: your circle
object will still be copied but it will also be boxed into a reference.
Now, .NET could theoretically allow you to inherit a struct
from a class
. Then the above code would work just as well as if Shape
were an interface. But then, the whole advantage of having a struct
in the first place vanishes: for all intents and purposes (except for local variables which never get passed to another method, hence no utility of inheritance) your struct
would behave as an immutable reference type instead of a value type.
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