可能重复:
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需要演员才能工作。我不确定我是做错了什么,还是在第二种场景中确实需要演员。
有人对它有所了解吗?
答案 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)
答案 3 :(得分:0)
第二个场景需要强制转换,因为您的LINQ表达式投影到派生对象列表(List<DealBookmarkWrapper>
)。但是,您想要的是创建基础对象列表(List<BookmarkWrapper>
)。由于您希望编译器“丢失”某些类型信息,因此您需要明确它。
最好的解决方案是在Cast<BookmarkWrapper>
调用之前插入.ToList
,使其明确并保持可读的语法:
var bm2 = deals.Select(d => new DealBookmarkWrapper(d))
.Cast<BookmarkWrapper>()
.ToList();