返回一个数组和一个IList <>有什么区别?(RE:Eric Lippert的有害阵列)

kdb*_*man 3 c# arrays collections

我刚刚阅读了Eric Lippert的" Arrays被认为是有害的 "文章.他告诉他的读者,他们"可能不应该将数组作为公共方法或财产的价值返回",其理由如下(稍微解释):

现在调用者可以使用该数组并用他们喜欢的任何内容替换它的内容.回归的明智之举是IList<>.你可以自己构建一个很好的只读集合对象,然后根据需要传递对它的引用.

在本质上,

数组是变量的集合.调用者不需要变量,但是如果这是获取值的唯一方法,它将采用它们.但是被调用者和调用者都不希望这些变量发生变化.

为了理解变量与值的含义,我构建了具有ArrayIList<>字段的demo类,以及返回对两者的引用的方法. 这是在C#Pad上.

class A {

    private readonly int[] arr = new []
    {
        10, 20, 30, 40, 50    
    };

    private readonly List<int> list = new List<int>(new []
    {
        10, 20, 30, 40, 50
    });

    public int[] GetArr()
    {
        return arr;
    }

    public IList<int> GetList()
    {
        return list;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我理解正确,这种GetArr()方法是Lippert的不良做法,GetList()是他明智的做法.这是一个不良调用者可变性行为的演示GetArr():

var a = new A();
var arr1 = a.GetArr();
var arr2 = a.GetArr();

Console.WriteLine("arr1[2]: " + arr1[2].ToString());  // > arr1[2]: 30
Console.WriteLine("arr2[2]: " + arr2[2].ToString());  // > arr2[2]: 30

// ONE CALLER MUTATES
arr1[2] = 99;

// BOTH CALLERS AFFECTED
Console.WriteLine("arr1[2]: " + arr1[2].ToString());  // > arr1[2]: 99
Console.WriteLine("arr2[2]: " + arr2[2].ToString());  // > arr2[2]: 99
Run Code Online (Sandbox Code Playgroud)

但我不明白他的区别- IList<>参考值具有相同的来电者的突变的问题:

var a = new A();
var list1 = a.GetList();
var list2 = a.GetList();

Console.WriteLine("list1[2]: " + list1[2].ToString());  // > list1[2]: 30
Console.WriteLine("list2[2]: " + list2[2].ToString());  // > list2[2]: 30

// ONE CALLER MUTATES
list1[2] = 99;

// BOTH CALLERS AFFECTED
Console.WriteLine("list1[2]: " + list1[2].ToString());  // > list1[2]: 99
Console.WriteLine("list2[2]: " + list2[2].ToString());  // > list2[2]: 99
Run Code Online (Sandbox Code Playgroud)

显然,我相信Eric Lippert知道他在说什么,所以我在哪里误解了他?返回的IList<>引用以什么方式比引用更安全Array

Ser*_*rvy 5

如果这篇文章今天已经写好了几乎肯定会建议使用IReadOnlyList<T>,但是在撰写该文章的2008年并不存在这种类型.具有只读可索引列表接口的唯一受支持的方法是使用IList<T>并且根本不实现变异操作.这确实让你返回一个调用者不能改变的对象,尽管它不一定清楚(特别是来自API)该对象实际上是不可变的.从那时起,.NET中的这个缺点就得到了补救.