【问题标题】:Cannot convert from an IEnumerable<T> to an ICollection<T>无法从 IEnumerable<T> 转换为 ICollection<T>
【发布时间】:2014-08-26 22:05:09
【问题描述】:

我已经定义了以下内容:

public ICollection<Item> Items { get; set; }

当我运行这段代码时:

Items = _item.Get("001");

我收到以下消息:

Error   3   
Cannot implicitly convert type 
'System.Collections.Generic.IEnumerable<Storage.Models.Item>' to 
'System.Collections.Generic.ICollection<Storage.Models.Item>'. 
An explicit conversion exists (are you missing a cast?)

谁能解释我做错了什么。我很困惑 Enumerable、Collections 和使用 ToList() 的区别

添加信息

稍后在我的代码中,我有以下内容:

for (var index = 0; index < Items.Count(); index++) 

我可以将 Items 定义为 IEnumerable 吗?

【问题讨论】:

  • 你能提供更多关于_item的类型和Get(string)的签名(特别是返回类型)的信息吗?
  • 为什么不这样改类型呢? public IEnumerable&lt;Item&gt; Items { get; set; }ICollection有什么特别的原因吗?
  • IEnumerable Get(string pk);

标签: c# .net


【解决方案1】:

ICollection&lt;T&gt; 继承自 IEnumerable&lt;T&gt; 所以分配结果

IEnumerable<T> Get(string pk)

ICollection&lt;T&gt; 有两种方法。

// 1. You know that the referenced object implements `ICollection<T>`,
//    so you can use a cast
ICollection<T> c = (ICollection<T>)Get("pk");

// 2. The returned object can be any `IEnumerable<T>`, so you need to 
//    enumerate it and put it into something implementing `ICollection<T>`. 
//    The easiest is to use `ToList()`:
ICollection<T> c = Get("pk").ToList();

第二个选项更灵活,但对性能的影响更大。另一种选择是将结果存储为IEnumerable&lt;T&gt;,除非您需要ICollection&lt;T&gt; 接口添加的额外功能。

附加性能评论

你的循环

for (var index = 0; index < Items.Count(); index++)

IEnumerable&lt;T&gt; 上工作,但效率低下;每次调用Count() 都需要完整 枚举所有元素。使用集合和 Count 属性(不带括号)或将其转换为 foreach 循环:

foreach(var item in Items)

【讨论】:

  • ICollection 增加了什么附加功能?
  • ICollection&lt;T&gt; 可以被操纵(详见doc),而IEnumerable&lt;T&gt; 只能被枚举。
  • 我需要一些可以运行不同 LINQ 查询的东西。我不需要在列表中添加或做任何类似的事情。这是否意味着使用 ICollection 会更好。
  • LINQ 在IEnumerable&lt;T&gt; 上工作,所以IEnumerable&lt;T&gt; 在这种情况下就足够了。
【解决方案2】:

您不能直接从IEnumerable&lt;T&gt; 转换为ICollection&lt;T&gt;。您可以使用IEnumerable&lt;T&gt;ToList 方法将其转换为ICollection&lt;T&gt;

someICollection = SomeIEnumerable.ToList();

【讨论】:

  • 这对我有用。但是对我来说转换是一个好主意还是我会更好地使用 IEnumerable 作为 Items 的类型。如果我使用 IEnumerable,我是否会这样做,以便在我的程序稍后需要时对项目执行更多操作?
  • ICollection 已经实现了 IEnumerable。如果您担心可用的操作,我认为您应该选择 ICollection。如果您可以阅读两者之间的实际差异,然后决定实际要使用什么,那就更好了
  • 我试图了解如果我使用 ToList() 会有什么优势。获得数据后,我想对项目运行 LINQ 查询。
  • ToList() 将起作用,但正如您在 cmets Get() 中所述,返回一个 ICollection,所以实际上您只需要对 ICollection 进行强制转换,或者更好的是,更改返回Get 到 ICollection 的签名。使用 ToList 或 ToArray 会起作用,但也会导致不必要的创建内存/复制操作
  • 您可以对 IEnumerable 和 ICollection 运行 LINQ 查询。优点.. 我现在知道的一个是 Count ICollection 通过计算它有多少项目来维护计数和 IEnumerable 返回结果。 ICollection 提供了额外的删除方法,而 Ienumerables 没有
【解决方案3】:

关于该问题的更多信息:

请提供更多关于物品类型和Get签名的信息

您可以尝试以下两件事:

  • 将_item.Get的返回值转换为(ICollection)
  • 其次使用 _item.Get("001").ToArray() 或 _item.Get("001").ToList()

请注意,第二个会导致阵列副本的性能下降。如果 Get 的签名(返回类型)不是 ICollection,则第一个将不起作用,如果不是 IEnumerable,则第二个将不起作用。


根据您对问题和 cmets 的澄清,我会亲自向 ICollection 声明 _item.Get("001") 的返回类型。这意味着您不必进行任何涉及不必要的创建/复制操作的转换或转换(通过 ToList / ToArray)。

// Leave this the same
public ICollection<Item> Items { get; set; }

// Change function signature here:
// As you mention Item uses the same underlying type, just return an ICollection<T>
public ICollection<Item> Get(string value); 

// Ideally here you want to call .Count on the collectoin, not .Count() on 
// IEnumerable, as this will result in a new Enumerator being created 
// per loop iteration
for (var index = 0; index < Items.Count(); index++) 

最好的问候,

【讨论】:

  • 签名为:IEnumerable Get(string pk); Items 用于保存返回的 Item 记录。稍后我遍历这些以创建报告。我可以使用任何有效的东西。你认为最好的数据类型是什么?
  • 我建议将 Items 的数据类型更改为 IEnumerable 以匹配 Get,或将 Get 的返回类型更改为 ICollection 以匹配 Items。我假设这两个是相同的底层类型,只是声明不同?如果它们是相同的类型,则要避免使用 ToList() 或 ToArray(),因为这会执行不必​​要的内存分配和数组复制。如果它们不是同一类型,则必须进行一些转换
  • 我添加到问题中以显示我以后在哪里使用项目。当你说相同的基础类型时,你是正确的。
  • 好的,那我就改变Get的返回类型,因为这样你就不需要做任何转换(通过ToList / ToArray,这很慢),或者转换。希望这会有所帮助:)
猜你喜欢
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多