How can interfaces implement progressively more-strict typed properties?
I'm working on a series of data structures. Some require a specific number of dimensions (like quad-trees or oct-trees) and some allow for any number (such as kd-trees). I'd like to implement my different structures and interfaces as follows:
public struct Point : IPoint // An n-dimensional point
public struct Point2D : IPoint // A 2-dimensional point
public interface IPointEntity
{
IPoint Location { 开发者_如何学编程get; }
}
public interface IPointEntity2D : IPointEntity
{
Point2D Location { get; }
}
This way, I can create classes like this:
public class Quadtree
{
public void Add(IPointEntity2D value) {...}
}
public class KdTree
{
public void Add(IPointEntity value) {...}
}
However, I'm told that IPointEntity2D
must declare Location
as New
since it hides IPointEntity.Location
. This defeats the purpose, though, as I would have to implement them both separately. It seems to me that the 2D implementation should fulfill the n-D interface's requirement. How can I accomplish this?
EDIT: I've now got it implemented as per Jon Skeet's suggestion:
public struct Point : IPoint // An n-dimensional point
public struct Point2D : IPoint // A 2-dimensional point
public interface IPointEntity<T> where T : IPoint
{
T Location { get; }
}
public class Quadtree<T> where T : IPointEntity<Point2D>
{
public void Add(T value) {...}
}
public class KdTree<T> where T : IPointEntity<IPoint>
{
public void Add(T value) {...}
}
But when I try to make an entity, I can't use them in both appropriate classes, like I had hoped:
public class Sprite2D : IPointEntity<Point2D>
{
public Point2D Location { get; set; }
}
public class Sprite3D : IPointEntity<Point3D>
{
public Point3D Location { get; set; }
}
static void Main(string[] args)
{
var quadtree = new Quadtree<Sprite2D>(); // Works just great
var kdTree2D = new KdTree<Sprite2D>(); // Doesn't work
var kdTree3D = new KdTree<Sprite3D>(); // Doesn't work
}
You're looking for covariant return types - they just don't exist in .NET. You have to implement the two properties separately, using explicit interface implementation to avoid them clashing.
One potential workaround is to use a generic interface instead:
public interface IPointEntity<T> where T : IPoint
{
T Location { get; }
}
Note that this would also allow a class to implement IPointEntity<Point>
and avoid boxing a Point
into an IPoint
when it's accessed.
You could use a generic interface
public interface IPointEntity<T> where T : IPoint
{
T Location { get; }
}
and let IPointEntity2D
inherit IPointEntity<Point2D>
.
精彩评论