我有一个名为 ComicBookRepository 的对象,其中包含漫画书类型的列表( _comicBooks )。
作为此实现的一部分,我有一个名为 GetComicBook()的方法,其中包含一个参数' Id' int 类型,返回漫画书,其中Id属性与传入的int参数匹配。
ComicBook comicBook = null;
foreach (var book in _comicBooks)
{
if (book.Id == id)
{
comicBook = book;
break;
}
}
return comicBook;
我正在尝试使用现有代码(可以工作)并使用匿名类型将其转换为LINQ表达式,如下所示:
var comicBook = from book in _comicBooks
where book.Id == id
select new
{
Id = book.Id,
SeriesTitle = book.SeriesTitle,
IssueNumber = book.IssueNumber,
DescriptionHtml = book.DescriptionHtml,
Artists = book.Artists,
Favorite = book.Favorite
};
return (ComicBook)comicBook;
但是此代码返回InvalidCastException:
InvalidCastException: Unable to cast object of type 'WhereSelectArrayIterator`2[ComicBooksGallery.Models.ComicBook,<>f__AnonymousType0`6[System.Int32,System.String,System.Int32,System.String,ComicBooksGallery.Models.Artist[],System.Boolean]]' to type 'ComicBooksGallery.Models.ComicBook'.
我说我的LINQ查询会返回IEnumerable<anonymous type>
吗?为什么我不能将它转换为漫画书?此外,我的匿名类型中设置的属性与漫画书中找到的属性完全匹配。编译器是否能够推断出它的类型而不必明确地转换为漫画书?任何帮助将非常感激。谢谢!
修改
正如Scott Hannen和Nkosi指出的那样,我需要从查询中选择一个元素,因为它返回了一个COLLECTION。另外,我需要在LINQ本身中指定类型。工作代码如下所示:
public ComicBook GetComicBook(int id)
{
//ComicBook comicBook = null;
//foreach (var book in _comicBooks)
//{
// if (book.Id == id)
// {
// comicBook = book;
// break;
// }
//}
// TODO:
// convert foreach above to linq.
// projection - project results of linq to an anonymous type.
//var comicBook = (from book in _comicBooks
// where book.Id == id
// select new ComicBook
// {
// Id = book.Id,
// SeriesTitle = book.SeriesTitle,
// IssueNumber = book.IssueNumber,
// DescriptionHtml = book.DescriptionHtml,
// Artists = book.Artists,
// Favorite = book.Favorite
// }).FirstOrDefault();
//return comicBook;
// third times a charm.
// one statement shouldn't have this much power ;)
return _comicBooks.First(c => c.Id == id);
}
编辑2:
有几个人很友好地指出 - 整个事情可以简化为使用Lambda语法的单行代码!
答案 0 :(得分:5)
如果您设置的属性 - Id
,SeriesTitle
等等都是ComicBook
的可设置属性,则更改
select new
{
到
select new ComicBook
{
由于您选择了ComicBook
Id
(并且显然试图返回单个ComicBook
),因此您希望查询只返回一个结果。即使是这种情况,Select
仍然会返回包含一个项目的结果集。
要从结果集中获取该项,请添加到结尾
.First()
如果应该总是有一个或多个结果。如果没有结果,它会抛出异常。.Single()
会抛出异常。 .FirstOrDefault()
返回第一个项目,如果没有项目,则返回null。如果_comicBooks
是List<ComicBook>
(或其他IEnumerable<ComicBook>
),您甚至可以将整个事情减少到
return _comicBooks.First(cb => cb.Id == id);
(或FirstOrDefault
或Single
。)
new ComicBook
创建一个与查询返回的属性相同的新实例。如果由于某种原因你需要创建一个新的实例,你可以这样做,但你可能不需要。