我正在阅读Eric Lippert撰写的博客,他解释了为什么他几乎从不使用数组,以下部分让我很好奇:
如果您正在编写这样的API,请将数组包装在ReadOnlyCollection中并返回IEnumerable或IList或其他内容,但不返回数组. (当然,不要简单地将数组转换为IEnumerable并认为你已经完成了!那仍然是传递变量;调用者可以简单地转换回数组! 只有在读取数据时才传递出一个数组 -唯一的对象.)
所以我在收藏中乱七八糟:
string[] array = new[] { "cat", "dog", "parrot" }; IEnumerabletest1 = array.AsEnumerable(); string[] secondArray = (string[])test1; //array1[0] is now also "whale" array[0] = "whale"; //11 interfaces var iArray = array.GetType().GetInterfaces(); //Still 11 interfaces?? var iTest1 = test1.GetType().GetInterfaces();
我初始化数组,然后使用该AsEnumerable()
方法就可以将其转换为一个IEnumerable
(或因此我认为),但是当我将它转换回一个新的阵列,和原来的数组中改变一个值,值test1
,并secondArray
得到了改变,以.显然我只是对原始数组进行了2次新引用,而不是创建一个IEnumerable
像ToArray()
返回一个新数组的新引用.
当我比较数组的接口时IEnumerable
,它们都具有相同的接口.如果数组实际上没有做任何事情,为什么数组有这个方法呢?我知道AsEnumerable()
它有用Linq-to-entities来获取可枚举的方法IQueryable
,但是为什么要将这个方法添加到数组中呢?这种方法有实际用途吗?
编辑: Tim Schmelter的评论提出了一个非常好的观点,不应该被忽视:
"它没有那么无用.你可以在不破坏其余代码的情况下改变实际类型.所以你可以用数据库查询或列表或hashset或其他任何东西替换数组,但是AsEnumerable总是有效,其余的代码也是如此所以AsEnumerable就像一份契约."
AsEnumerable
只是一种将价值投入的方式IEnumerable
.它不会创建新对象.该方法的实现如下:
public static IEnumerableAsEnumerable (this IEnumerable source) { return source; }
它根本不是创建一个新对象.
它有用的原因:
如果一个对象实现IEnumerable
,但也有一个名为实例方法Select
,Where
等等,你不能使用LINQ方法. AsEnumerable
让你把它转换IEnumerable
为避免这种过载冲突.
如果要将对象转换为IEnumerable
(无论出于何种原因),但是T
是匿名类型,则不能使用强制类型转换,您需要一个可以推断其泛型参数的泛型方法来执行此操作.
你在这里有几个好的答案; 我想我会添加一些支持点.
首先,FYI,这样一个总是返回其参数的"无所事事"方法称为"身份",原因很明显,输出与输入相同.身份似乎毫无用处,但实际上它们确实会不时派上用场.
其次,如果您确实希望将数组转换为不具有数组引用标识的只读序列,则可以进行标识投影:
var sequence = from item in array select item;
或等效地:
var sequence = array.Select(item => item);
请注意,这里的投影是一个身份; 我说他们很有用.
通常LINQ会优化身份投射; 如果你说
from item in array where whatever select item;
那么最后的身份投射永远不会产生,因为这只是浪费时间.也就是说,这意味着
array.Where(item => whatever)
不
array.Where(item => whatever).Select(item => item)
但编译器不能抑制的情况下身份投影,其中select
是只在查询的事情,正是这样就可以使无法转换回原来的阵列的投影.