Как передать список, когда тип param-List?
как я могу передать список, который является списком DerivedObjects, где метод ожидает список BaseObjects. Я конвертирую список .ToList<BaseClass>()
и мне интересно, есть ли лучший способ. Моя вторая проблема заключается в неправильном синтаксисе. Я пытаюсь передать список byref, и я получаю сообщение об ошибке:'ref' argument is not classified as a variable
как я могу исправить эти две проблемы? спасибо.
public class BaseClass { }
public class DerivedClass : BaseClass { }
class Program
{
static void Main(string[] args)
{
List<DerivedClass> myDerivedList = new List<DerivedClass>();
PassList(ref myDerivedList.ToList<BaseClass>());
// SYNTAX ERROR ABOVE IS - 'ref' argument is not classified as a variable
Console.WriteLine(myDerivedList.Count);
}
public static void PassList(ref List<BaseClass> myList)
{
myList.Add(new DerivedClass());
Console.WriteLine(myList.Count);
}
}
решила:
метод, подобный этому, решил мою проблему.
public static void PassList<T>(ref List<T> myList) where T : BaseClass
{
if (myList == null) myList = new List<T>();
// sorry, i know i left this out of the above example.
var x = Activator.CreateInstance(typeof(T), new object[] {}) as T;
myList.Add(x);
Console.WriteLine(myList.Count);
}
спасибо всем, кто помогает по этому вопросу и от других вопросов SO.
3 ответов
на ref
часть проста: чтобы передать аргумент по ссылке, он должен быть переменной, в основном. Так можно написать:
List<BaseClass> tmp = myDerivedList.ToList<BaseClass>();
PassList(ref tmp);
... но это! .. --18-->не влияет на значение myDerivedList
или само содержание.
на ref
здесь бессмысленно в любом случае, так как вы никогда не меняете значение myList
в рамках метода в любом случае. Важно понимать разницу между изменением значения параметра и изменение содержания объект, на который ссылается значение параметра. См.моя статья о передаче параметров для получения более подробной информации.
теперь о том, почему вы не можете передать свой список - это сохранить безопасность типов. Предположим, вы ... --18-- > мог бы сделайте это, и мы могли бы написать:
List<OtherDerivedClass> list = new List<OtherDerivedClass>();
PassList(list);
теперь это будет попытка добавить экземпляр DerivedClass
до List<OtherDerivedClass>
- это как добавить яблоко к бананам... не работает! Компилятор C# не позволяет вам выполнять эта небезопасная операция - она не позволит вам относиться к бананам как к миске с фруктами. Предположим, мы ... --18-->сделал есть Fruit
вместо BaseClass
и Banana
/ Apple
как два производных класса, с PassList
добавлять Apple
к списку дано:
// This is fine - you can add an apple to a fruit bowl with no problems
List<Fruit> fruitBowl = new List<Fruit>();
PassList(fruitBowl);
// This wouldn't compile because the compiler doesn't "know" that in PassList
// you're only actually adding an apple.
List<Apple> bagOfApples = new List<Apple>();
PassList(bagOfApples);
// This is the dangerous situation, where you'd be trying to really violate
// type safety, inserting a non-Banana into a bunch of bananas. But the compiler
// can't tell the difference between this and the previous one, based only on
// the fact that you're trying to convert a List<Banana or Apple> to List<Fruit>
List<Banana> bunchOfBananas = new List<Banana>();
PassList(bunchOfBananas );
C# 4 позволяет общая дисперсия в некоторых ситуациях - но это не поможет в данном конкретном случае, как вы делаете что-то принципиально небезопасной. Общая дисперсия является довольно сложной тема, хотя-поскольку вы все еще узнаете о том, как работает передача параметров, я бы сильно предложите оставить его в покое на данный момент, пока вы не будете более уверены в остальном языке.
Если вы должны держать ref
, вы можете сделать это:
var list = myDerivedList.ToList<BaseClass>();
PassList(ref list);
// SYNTAX ERROR ABOVE IS - 'ref' argument is not classified as a variable
на ref
параметр, ему нужна переменная для ссылка. При создании на лету нет ничего, чтобы ссылаться позже в коде, поэтому это действительно не имеет смысла.
во-первых, в коде, который вы предоставили, вам не нужен ref
потому что вы на самом деле не меняете назначения (ссылка) myList в любом случае.
Тогда, конечно, вы получите ошибку с ref myDerivedList.ToList<..>()
потому что с byref вы можете изменить, где указана переменная, но вы не даете переменную, вы даете стоимостью (так что просто прочитайте компилятор жаловаться ;))
к вам указывают: читайте о Ко - и контравариантность - если вы используете .net 4.0