Передача списка по ref, когда IList по ref является сигнатурой метода
У меня проблемы с кодом ниже. Я хочу, чтобы мой метод использовал список IList, а не список. Но заблуждаюсь ли я?
Вот мой метод:
public void DoFoo( ref IList<Foo> thingy) {}
Вот объявление и звонок:
var foo = new List<Foo>();
DoFoo( ref foo)
Почему это не скомпилируется? foo определенно реализует IList Если это потому, что компиляция должна будет привести из List к IList?
2 ответа
Вывод типа мешает здесь. var
эквивалентно объявлению List
напрямую, но вы хотите IList
, Вы должны будете явно указать ожидаемый тип в своем объявлении.
IList<foo> foo = new List<Foo>();
DoFoo( ref foo)
Причина, по которой он не компилируется, состоит в том, что ref
позволяет методу сделать это:
public void DoFoo( ref IList<Foo> thingy)
{
thingy = new Foo[10];
}
Массивы реализуют IList<T>
, но они не List<T>
и именно поэтому компилятор отказывается компилировать код.
У вас есть параметр, который ссылается на переменную определенного типа, в этом случае List<Foo>
и вы не можете запихивать туда другие типы коллекций, если они не наследуются от List<Foo>
,
Есть один способ обойти это, просто скопировать список в переменную правильного типа, но вам также нужно решить, что произойдет, если метод фактически заменит содержимое этой переменной.
Другими словами, вы можете сделать это:
IList<Foo> il = foo;
DoFoo(ref il);
// what if il is a new reference here now?
Как уже упоминалось в другом ответе, объекты (и, следовательно, списки в данном случае) уже являются ссылками. Вы уверены, что вам нужно ref
на первом месте? Позвольте мне уточнить. Объекты в.NET являются ссылочными типами, что означает, что вы передаете ссылку на объект. Используя ref
Параметр позволяет передавать параметр по ссылке, который отличается.
Передача ссылки позволяет методу получить доступ к тому же объекту, что и внешний мир. Передача по ссылке позволяет методу получить доступ к переменной во внешнем мире.