无法将IEnumerable转换为指定的类型

时间:2017-12-11 02:05:00

标签: c# asp.net-mvc linq collections anonymous-types

我有一个名为 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语法的单行代码!

1 个答案:

答案 0 :(得分:5)

如果您设置的属性 - IdSeriesTitle等等都是ComicBook的可设置属性,则更改

select new
{

select new ComicBook
{

由于您选择了ComicBook Id(并且显然试图返回单个ComicBook),因此您希望查询只返回一个结果。即使是这种情况,Select仍然会返回包含一个项目的结果集

要从结果集中获取该项,请添加到结尾

  • .First()如果应该总是有一个或多个结果。如果没有结果,它会抛出异常。
  • 除非查询返回一个结果,否则
  • .Single()会抛出异常。
  • .FirstOrDefault()返回第一个项目,如果没有项目,则返回null。

如果_comicBooksList<ComicBook>(或其他IEnumerable<ComicBook>),您甚至可以将整个事情减少到

return _comicBooks.First(cb => cb.Id == id);

(或FirstOrDefaultSingle。)

new ComicBook创建一个与查询返回的属性相同的新实例。如果由于某种原因你需要创建一个新的实例,你可以这样做,但你可能不需要。