1

可能重复:
是否可以在不使用 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

4 回答 4

7

您的问题有两个方面:

  • 的类型参数TToList<T>编译器推断为DealBookmarkWrapper,因此List<DealBookmarkWrapper产生了 >。
  • 由于List<T>不是协变类型,因此无法从List<DealBookmarkWrapper> 到进行保留表示的转换List<BookmarkWrapper>。有关为什么会这样的更多信息,请参阅此问题

您已经发现在Select投影中添加演员表是一种解决方法。另一种方法是,在 C# 4 + .NET 4.0(或更高版本)中,显式指定类型参数并依赖于IEnumerable<T>

deals.Select(d => new DealBookmarkWrapper(d))
     .ToList<BookmarkWrapper>()
于 2012-09-17T15:28:05.980 回答
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>

于 2012-09-17T15:27:47.150 回答
1

你没有做错任何事。List<T>不是协变的,因此您需要显式转换对象。更多信息在这里

于 2012-09-17T15:31:13.873 回答
0

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

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

var bm2 = deals.Select(d => new DealBookmarkWrapper(d))
               .Cast<BookmarkWrapper>()
               .ToList(); 
于 2012-09-17T15:26:12.190 回答