Как передать список, когда тип 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