试图将foreach转换为linq等价物

时间:2012-09-17 15:22:10

标签: c# linq

  

可能重复:
  Is it possible to recreate this statement without using a foreach?

我有2个共享基类的类

DealBookmarkWrapper : BookmarkWrapper
StoreBookmarkWrapper : BookmarkWrapper

我还有以下声明:

// 1 - This works
List<BookmarkWrapper> bm = new List<BookmarkWrapper>();
foreach(var d in deals)
{
    bm.Add(new DealBookmarkWrapper(d));
}

// 2 - This does not work
List<BookmarkWrapper> bm2 = deals.Select(d => new DealBookmarkWrapper(d)).ToList();

1)工作原样,但2需要演员才能工作。我不确定我是做错了什么,还是在第二种场景中确实需要演员。

有人对它有所了解吗?

4 个答案:

答案 0 :(得分:7)

你的问题有两个方面:

  • T的类型参数ToList<T>由编译器推断为DealBookmarkWrapper,因此List<DealBookmarkWrapper&gt;生产。
  • 由于List<T>不是协变类型,因此List<DealBookmarkWrapper&gt;不提供任何表示保留转换。到List<BookmarkWrapper>。有关具体原因的详细信息,请参阅this question

您已经发现在Select投影中添加强制转换可以解决这个问题。另一种方式,在C#4 + .NET 4.0(或更高版本)中,将明确指定type-argument并依赖IEnumerable<T>的协方差:

deals.Select(d => new DealBookmarkWrapper(d))
     .ToList<BookmarkWrapper>()

答案 1 :(得分:2)

List<BookmarkWrapper> bm2 = deals.Select(d => new DealBookmarkWrapper(d)).Cast<BookmarkWrapper>().ToList(); 

List<BookmarkWrapper> bm2 = deals.Select(d => (BookmarkWrapper)(new DealBookmarkWrapper(d))).ToList(); 

您创建的代码List<DealBookmarkWrapper>,无法转换为List<BookmarkWrapper>。列表的类型由C#的类型推断算法确定。

上面的两个选项都会创建DealBookmarkWrapper个对象,但会将引用转换为BookmarkWrapper,因此类型推断会将类型解析为List<BookmarkWrapper>

答案 2 :(得分:1)

你没有做错任何事。 List<T>不是covariant,因此您需要显式转换对象。更多信息here

答案 3 :(得分:0)

第二个场景需要强制转换,因为您的LINQ表达式投影到派生对象列表(List<DealBookmarkWrapper>)。但是,您想要的是创建基础对象列表(List<BookmarkWrapper>)。由于您希望编译器“丢失”某些类型信息,因此您需要明确它。

最好的解决方案是在Cast<BookmarkWrapper>调用之前插入.ToList,使其明确并保持可读的语法:

var bm2 = deals.Select(d => new DealBookmarkWrapper(d))
               .Cast<BookmarkWrapper>()
               .ToList();