13

我如何传递一个列表,该列表是一个 DerivedObjects 列表,其中该方法需要一个 BaseObjects 列表。我正在转换列表.ToList<BaseClass>(),想知道是否有更好的方法。我的第二个问题是语法不正确。我正在尝试通过引用传递列表,但出现错误:'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 问题的人。

4

3 回答 3

19

ref部分很简单:通过引用传递参数,基本上它必须是一个变量。所以你可以写:

List<BaseClass> tmp = myDerivedList.ToList<BaseClass>();
PassList(ref tmp);

...但这不会影响价值myDerivedList或内容本身。

无论如何,这里ref毫无意义,因为无论如何您都不会更改myList方法内的值。了解更改参数值与更改参数值所指对象的内容之间的区别很重要。有关详细信息,请参阅我关于参数传递的文章。

现在至于为什么你不能传递你的列表 - 这是为了保护类型安全。假设你可以这样做,我们可以这样写:

List<OtherDerivedClass> list = new List<OtherDerivedClass>();
PassList(list);

现在这将尝试向DerivedClassa添加一个实例List<OtherDerivedClass>- 这就像将一个苹果添加到一堆香蕉中......它不起作用!C# 编译器会阻止您执行不安全的操作 - 它不会让您将一堆香蕉视为水果盘。假设我们确实Fruit代替BaseClass, 和Banana/Apple作为两个派生类,PassList并将 an 添加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 在某些情况下允许泛型变化- 但在这种特殊情况下它无济于事,因为您正在做一些根本不安全的事情。不过,泛型方差是一个相当复杂的话题——因为你仍在学习参数传递的工作原理,我强烈建议你暂时不要管它,直到你对语言的其余部分更有信心。

于 2011-10-04T04:19:22.933 回答
3

如果你必须保留ref,你可以这样做:

var list = myDerivedList.ToList<BaseClass>();
PassList(ref list);
// SYNTAX ERROR ABOVE IS - 'ref' argument is not classified as a variable

对于ref参数,它需要一个变量来引用。当动态创建时,以后在代码中没有什么可以引用的,所以它真的没有意义。

于 2011-10-04T04:18:23.757 回答
0

首先,在您提供的代码中,您不需要,ref因为您实际上并没有以任何方式更改目标(引用) myList 。然后当然你会得到一个错误,ref myDerivedList.ToList<..>()因为使用 byref 你可以改变一个变量指向的位置,但是你没有给出一个变量,你给出了一个(所以只需阅读编译器的抱怨;))

对你来说:阅读协变和逆变- 如果你使用的是 .net 4.0

于 2011-10-04T04:19:41.837 回答