我正在阅读Eric Lippert的a blog,他解释了为什么他几乎不会使用数组,以下部分让我很好奇:
如果您正在编写这样的API,请将数组包装在ReadOnlyCollection中并返回IEnumerable或IList或其他内容,但不返回数组。 (当然,不要简单地将数组转换为IEnumerable并认为你已经完成了!那仍然是传递变量;调用者可以简单地转换回数组!只传递一个数组,如果它被只读对象包裹起来。)
所以我对收藏品进行了一些讨论:
string[] array = new[] { "cat", "dog", "parrot" };
IEnumerable<string> test1 = 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的评论提出了一个非常好的观点,不应该被忽视:
&#34;它没那么无用。您可以在不破坏其余代码的情况下更改实际类型。所以你可以用数据库查询或列表或者hashset等替换数组,但AsEnumerable总是可以工作,其余代码也可以。所以AsEnumerable就像合同一样。&#34;
答案 0 :(得分:11)
AsEnumerable
只是将值转换为IEnumerable<T>
的一种方法。它不会创建新对象。该方法的实现如下:
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{
return source;
}
根本没有创建新对象。
它有用的原因:
如果对象实现IEnumerable<T>
但也有一个名为Select
,Where
等的实例方法,则无法使用LINQ方法。 AsEnumerable
允许您将其转换为IEnumerable
以避免此类过载冲突。
如果您想将对象转换为IEnumerable<T>
(无论出于何种原因),但T
是匿名类型,则无法使用一个演员,你需要一个通用的方法来推断它的泛型参数。
答案 1 :(得分:6)
你在这里有几个好的答案;我以为我会添加一些支持点。
首先,仅供参考,a&#34;什么都不做&#34;像这样总是返回其参数的方法称为&#34; identity&#34;,原因很明显,输出与输入相同。身份似乎毫无用处,但实际上它们确实会不时派上用场。
其次,如果您确实希望将数组转换为与数组没有引用标识的只读序列,则可以进行标识投影:
<div class="view-wrapper">
... view content ...
</div>
或等效地:
var sequence = from item in array select item;
请注意,这里的投影是一个身份;我说他们很有用。
通常LINQ会优化身份投射;如果你说
var sequence = array.Select(item => item);
然后永远不会生成最终的身份投影,因为这只是浪费时间。也就是说,这意味着
from item in array where whatever select item;
不
array.Where(item => whatever)
但是,如果array.Where(item => whatever).Select(item => item)
是查询中的唯一事物,编译器会不抑制身份投影,这正是为了让您可以制作投影无法转换回原始数组。
答案 2 :(得分:4)
AsEnumerable
的目的很明确,如Servy's answer和此帖所述:Why use .AsEnumerable() rather than casting to IEnumerable<T>?。
剩下的问题是:为什么IEnumerable<T>
上会显示?这种情况就是这种情况,因为此处使用的扩展方法使用IEnumerable<T>
作为其定义的类型。在ToString()
上将其视为string
。由于string
是一个对象,因此它派生方法ToString()
,但在string
的情况下却无用。在这里,扩展方法导致该方法的“无用”可用性。