Как интерфейсы могут реализовывать более строгие типизированные свойства? - PullRequest
2 голосов
/ 27 апреля 2011

Я работаю над серией структур данных.Некоторые требуют определенного числа измерений (например, квад-деревьев или окт-деревьев), а некоторые допускают любое количество (например, kd-деревьев).Я хотел бы реализовать свои различные структуры и интерфейсы следующим образом:

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; }
}

Таким образом, я могу создавать классы следующим образом:

public class Quadtree
{
    public void Add(IPointEntity2D value) {...}
}

public class KdTree
{
    public void Add(IPointEntity value) {...}
}

Однако мне сказали, что IPointEntity2D должен объявить Location как New, поскольку он скрывает IPointEntity.Location.Это побеждает цель, хотя, поскольку я должен был бы реализовать их обоих отдельно.Мне кажется, что реализация 2D должна соответствовать требованию интерфейса nD.Как я могу это сделать?


РЕДАКТИРОВАТЬ: Теперь я реализовал его в соответствии с предложением Джона Скита:

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) {...}
}

Но когда я пытаюсьсделать сущность, я не могу использовать их в обоих соответствующих классах, как я надеялся:

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
}

Ответы [ 2 ]

4 голосов
/ 27 апреля 2011

Вы ищете ковариантные типы возврата - они просто не существуют в .NET.Вы должны реализовать два свойства по отдельности, используя явную реализацию интерфейса, чтобы избежать их столкновения.

Один из возможных обходных путей - использовать вместо этого общий интерфейс:

public interface IPointEntity<T> where T : IPoint
{
    T Location { get; }
}

Обратите внимание, что это также позволяет классу реализовать IPointEntity<Point> и избегать вставки Point в IPoint при обращении к нему.

1 голос
/ 27 апреля 2011

Вы можете использовать универсальный интерфейс

public interface IPointEntity<T> where T : IPoint 
{
    T Location { get; }
}

и пусть IPointEntity2D наследует IPointEntity<Point2D>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...