There I am making a 2D game in C# XNA 4.0, and run across yet again a petty annoyance of mine; the Rectangle. For those using basic collision, this is almos
Inherit no, but you can add a lot of 'default' functionality to the Rectangle object with extension methods. For example
//(inside a static class)
public static int GetSurface(this Rectangle rect){return rect.Width * rect.Height;}
//calling
Rectangle rect;
var s = rect.GetSurface();
That said, what I normally do is encapsulate said struct. Use that class as the base object, and add an operator so that it can be implicitly cast to a Rectangle. That way it can be passed to a method that needs a rectangle without casting.
public class MyRect //class so you can inherit from it, but you could make your own struct as well
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int Right { get { return X + Width; } }
public int Bottom{ get { return Y + Height; } }
public static implicit operator Rectangle(MyRect rect)
{
return new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
}
public static implicit operator MyRect(Rectangle rect)
{
return new MyRect { X = rect.X, Y = rect.Y, Width = rect.Width, Height = rect.Height };
}
}
}
Now you can create your own rect manually or from an existing one:
MyRect rect = ARectangleVar
And you can use it in legacy methods that expect a Rectangle without casting
Here's a possible workaround (put this in MyClass
, the class you speak of that has a Rectangle property):
public static implicit operator Rectangle(MyClass obj)
{
return obj.Rectangle;
}
This will, e.g. allow you to pass your object to a method expecting a Rectangle
, and it work. Note that unlike with true inheritance, the Rectangle that exists isn't the same instance of MyClass
that you passed in, it's just a struct made from the value.
Value types are fundamentally incompatible with the style of inheritance that is applicable to class types, but it would be helpful to be able to declare a "derived struct" in such a way that the compiler would recognize a bidirectional identity-preserving conversion between the derived type and the original. The derived struct would be required to have exactly one field, called "Base" (though a C# compiler could accept the keyword base
as a substitute), whose type was that of the struct being derived. All members of "Base" whose names did not match those of the surrounding type would be regarded as members of the enclosing structure.
The primary things a "derived struct" would offer, but which are presently lacking, would be:
I'm not sure any changes to the runtime would be required to support any of these features, if one accepts that an item of a boxed derived type may only be unboxed as that same derived type; allowing a boxed version of a struct to be cast directly to an instance of an identity-convertible derived one would be helpful, but might add complexity. I'm not sure if such behavior would be required to make generics work.
Unfortunately, I get the feeling that many of the people responsible for making this sort of decision really don't like value types. Because of some design decisions early in the history of .net (especially the lack of "const ref" parameters and a means of exposing properties by ref
), making structs work in semantically-correct fashion can be a challenge, and I think some of the implementers would rather use the problems with structs as an excuse not to improve .net's handling of them, than add features that would fix the problems.