Подтвердить что ты не робот

Невозможно преобразовать из списка <Bar> в список <Foo>

У меня есть такая настройка:

abstract class Foo {}
class Bar : Foo {}

и метод в другом месте этой формы:

void AddEntries(List<Foo>) {}

Я пытаюсь вызвать этот метод, используя список объектов типа Bar

List<Bar> barList = new List<Bar>()
AddEntries(barList);

но это дает мне ошибку:

не может преобразовываться из списка <Bar> для списка <Foo>

Во всяком случае, вокруг этой проблемы? Мне нужно сохранить определение метода с помощью абстрактного класса.

4b9b3361

Ответ 1

Вы можете сделать свой AddEntries общий и изменить его на

void AddEntries<T>(List<T> test) where T : Foo
{
    //your logic 
}

Посмотрите Ограничения на параметры типа для получения дополнительной информации.

Ответ 2

Прочитайте Ковариацию и контравариантность в generics от docs.microsoft.com, как это, в частности, раздел "Общие интерфейсы с параметрами ковариантного типа" будет охватывать сценарий, с которым вы работаете.

Короче говоря, если вы (можете) изменить подпись вашего метода AddEntries на:

static void AddEntries(IEnumerable<Foo> entries)

(Обратите внимание на использование IEnumerable<Foo> вместо List<Foo>), вы сможете делать то, что вы хотите сделать.

Конкретная разница здесь в том, что IEnumerable<T> и List<T> объявляются по-разному:

public interface IEnumerable<out T> : IEnumerable
public class List<T> : IList<T>, ... ...

Разница, которая имеет значение, - это out в объявлении IEnumerable<T>, которая указывает, что она ковариантна, что означает (с определением, взятым с docs.microsoft.com):

Ковариация. Позволяет использовать более производный тип, чем первоначально указано.

Ответ 3

Это запрещено по простой причине. Предположим, что ниже компилируется:

AddEntries(new List<Bar>());

void AddEntries(List<Foo> list)
{
   // list is a `List<Bar>` at run-time
   list.Add(new SomethingElseDerivingFromFoo()); // what ?!
}

Если ваш код будет скомпилирован, у вас есть небезопасное дополнение (что делает бессмысленные общие списки), где вы добавили SomethingElseDerivingFromFoo на самом деле List<Bar> (тип времени выполнения).

Чтобы решить вашу проблему, вы можете использовать generics:

void AddEntries<T>(List<T> list) where T:Foo
{

}