Как разрешить производные коллекции в универсальном методе - PullRequest
0 голосов
/ 05 июля 2019

У меня есть несколько классов, представляющих объекты, у которых у всех есть границы, описанные полем Unity Rect . (Zone, Room, Structure, Tunnel, Room ...)

Эти объекты часто размещаются в коллекциях. (List<Zone>, List<Room> ...)

Я хочу иметь один метод статической утилиты, который будет проверять, перекрывает ли один из них какие-либо границы из коллекции таких объектов, без необходимости приведения List с использованием LINQ.

public static bool BoundsOverlapsOtherBounds(Bounds bound, List<Bounds>)

Как мне использовать полиморфизм C #, интерфейсы, ковариацию для достижения этой цели без необходимости сначала приводить List<Room> или List<Zone> к List<Bounds>?

Мои попытки до сих пор всегда приводили к " Невозможно преобразовать X в Y" Ошибки компилятора.

Ответы [ 2 ]

1 голос
/ 05 июля 2019

Поскольку (как подразумевается) все эти типы уже наследуются от Bounds, вам не нужно приводить List<Room> или List<Zone> к List<Bounds>.

Вы можете сделать это:

bool BoundsOverlapsOtherBounds<T>(Bounds bound, List<T> bounds) where T : Bounds

Общее ограничение означает, что вы можете передать любой List<T> в метод, если T реализует или наследует Bounds.

Так что, если у вас есть List<Room>, вы можете передать его методу без явного приведения:

var rooms = new List<Room>();
var otherBounds = new Bounds();
var overlaps = BoundsOverlapsOtherBounds(otherBounds, rooms);

Вам даже не нужно указывать универсальный аргумент, потому что он выводится.


Если по какой-либо причине эти объекты не имеют общего типа, то, скорее всего, им следует это сделать. Наследование - это решение , но нам не нужно его использовать, чтобы типы имели общую характеристику. Иногда это рисует нас в угол. Интерфейс также может иметь смысл:

interface IHasBoundaries // not a great name?
{
    Boundaries Bounds { get; }
}

Это полиморфизм. Множество форм (или типов) могут реализовывать интерфейс, и вам абсолютно все равно, что отличает их - только то, что у них общего. Вы можете написать код, который имеет дело с IHasBoundaries, и в этом контексте вам нужно знать об этих объектах только то, что они реализуют интерфейс.

Тогда ваш метод выглядит так:

bool BoundsOverlapsOtherBounds<T>(IHasBoundaries bound, List<T> bounds) 
    where T : IHasBoundaries
0 голосов
/ 05 июля 2019

Проблема в том, что List<Zone> отличается от List<Bounds>. Вы можете добавить Room к List<Bounds>, но не к List<Zone>, поэтому они не могут быть преобразованы. Однако я предполагаю, что вы хотите только перебрать список границ и не изменять коллекцию, для этого вам понадобится только IEnumerable вместо List. Поскольку IEnumerable<Zone> функционирует так же, как и IEnumerable<Bounds>, это разрешено. Поэтому, если вы действительно хотите прочитать только элементы параметра bounds, измените сигнатуру на эту:

public static bool BoundsOverlapsOtherBounds(Bounds bound, IEnumerable<Bounds> bounds)

, который должен принимать любые List из (Zone, Room, …)

Надеюсь, это поможет

...