2015-08-03 3 views
3

Так что мне нужно было реализовать поиск с использованием вершин и ребер, которые уже вычисляются в другой части кода (я рассматриваю эту часть как черный ящик).Параметрирование общего интерфейса в объявлении класса

Так у меня есть свой график, со списком вершин и ребер:

class Graph { 
    List<Vertex> vertices; 
    List<Edge> edges; 
} 

Я решил сделать общую реализацию для поиска, и создали оболочку для вершин:

class Node<T> {...} 

и создал интерфейс для краев, так что я могу использовать их в поиске:

interface ISearchLink<T> {...} 

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

public static List<Node<T>> Search(List<Node<T>> nodes, List<ISearchLink<T>> links); 

сейчас, потому что края уже используют тип я хотел их, и держать его consitent с другой стороны, я изменил класс Грань заявление выглядеть следующим образом (и реализованы методы интерфейса):

class Edge : ISearchLink<Vertex> {...} 

так что теперь, когда я звоню поиска, он говорит, что я недопустимые аргументы

List<Node<T>> table = search(vertices, edges); 

, который, кажется, указывает что объявление Edge недействительно (хотя у меня нет жалоб от VS). Является ли это заявление недействительным, и если да, то почему нет ошибки? И если это не является недопустимым, то какая проблема? (Кажется, VS не может преобразовать список «Грань» в список «ISearchLink«Vertex»»)

редактирования: ошибки в конкретных являются:

The best overloaded method match for Node<Vertex>.search(System.Collections.Generic.List<Vertex>, System.Collections.Generic.List<ISearchLink<Vertex>>)' has some invalid arguments 

и

cannot convert from 'System.Collections.Generic.List<Edge>' to 'System.Collections.Generic.List<ISearchLink<Vertex>>' 
+0

«Недопустимые аргументы» часто является ошибкой во время выполнения, но если вы имеете дело с параметрами типа, это может быть ошибка времени компиляции. Можете ли вы указать точную ошибку, которую вы получаете в своем вопросе? –

+0

Должен ли ваш список узлов (и список краев) иметь тип List в определенном? Или можно искать в IEnumerables вместо этого? Я спрашиваю, потому что IEnumerable ковариантен в своем параметре типа, а List инвариантен, и вы, похоже, ожидаете ковариантного поведения. –

+0

@JerryFederspiel это может быть IEnumerable, я просто закончил использование List (потому что я не думал, что так оно делает) – MasterOfTwo

ответ

1

Проблема заключается в том, что ваш метод поиска принимает в списках:

public static List<Node<T>> Search<T>(List<Node<T>> nodes, List<ISearchLink<T>> links) 

Когда вы говорите «кажется, VS не может преобразовать List<Edge> в List<ISearchLink<Vertex>>», это потому, что List<Edge>действительно не a List<ISearchLink<Vertex>>. VS не должен конвертировать, как это для вас, потому что List<T> является invariant в T.

Говоря, что ваш метод должен принимать значение List, вы сообщаете вызывающему, что вы можете получить доступ и использовать элементы в этой коллекции (что означает, что тип, который вы ожидаете в качестве параметра, должен быть назначен из типа вызывающего), но вы также можете вставить что-то в эту коллекцию (это означает, что тип, предоставляемый вызывающим абонентом, должен быть назначаемым из того типа, который вы ожидаете)!Это блокирует вызывающего абонента для обеспечения точно ожидаемого типа.

IEnumerable<T>, с другой стороны, является ковариантным в T. Вы не можете вставлять новые предметы в IEnumerable<T>; вы можете получить только все. Это означает, что тип, который вы ожидаете в качестве параметра, должен быть назначен из типа, который предоставляет вызывающий объект, который соответствует ситуации, в которой вы ожидаете ISearchLink<T>, который можно назначить из Edge. Но это прекрасно, если тип, предоставляемый вызывающим абонентом, не может быть назначен из типа, ожидаемого в качестве параметра, потому что в этом направлении не будет никаких назначений.

Таким образом изменить функцию, чтобы иметь подпись,

public static List<Node<T>> Search<T>(List<Node<T>> nodes, IEnumerable<ISearchLink<T>> links) 

Теперь VS будет счастливо Преобразовать List<Edge> к IEnumerable<ISearchLink<Vertex>>, потому что он знает, что вы только собираетесь тянуть вещи из списка, а не делать такие вещи, как вставляя MyEvilSearchLink<Vertex>> в то, что на самом деле List<Edge>.

0

правильный заголовок функции будет

public static List<Node<T>> Search<T>(List<Node<T>> nodes, List<ISearchLink<T>> links) 
{ 

} 

не забывайте <T> после Search

Смежные вопросы