4

How do we retrieve the first item of a WhereSelectListIterator? Usually, I use a foreach loop to iterate. Is there a way to call the equivalent of myResult[0] or myResult.FirstOrDefault(). Both throw an error. myResult.ToList() doesn't work either. I am beginning to think that the only thing we can do with a WhereSelectListIterator is iterate with foreach.

Here is the scenario: I have created an Orchard Query with a Shape layout. The Shape Template contains the following code:

@{
    // content items is of type WhereSelectListIterator<T,T>
    var contentItems = Model.ContentItems;
    dynamic firstItem = null;

    // {"Cannot apply indexing with [] to an expression of type 'object'"}
    //// firstItem = contentItems[0];

    // {"'object' does not contain a definition for 'ToList'"}
    // var items = contentItems.ToList();

    // get the title of the first content item
    // this is what DOES work
    foreach (var contentItem in contentItems)
    {
        firstItem = contentItem;
        break;
    }
}

<h2>@(firstItem != null ? firstItem.TitlePart.Title : "Got Nothing")</h2>

Specifically, contentItems was of type

System.Linq.Enumerable.WhereSelectListIterator<
    Orchard.Projections.Descriptors.Layout.LayoutComponentResult,
    Orchard.ContentManagement.ContentItem>

Please let me know if you need more details about why I might want to retrieve the first item.

Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467

1 Answers1

7

The issue is that you have a dynamic object and the LINQ methods (ToList, FirstOrDefault) you are trying to use are extension methods on IEnumerable<T>. The DLR does not have enough information at runtime to resolve extension methods when they are invoked like instance methods. Since extension methods are really just static methods with special attributes attached, you can invoke them in the static style as well:

var contentItems = Model.ContentItems;
dynamic firstItem = System.Linq.Enumerable.FirstOrDefault(contentItems);
Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • 2
    Casting also worked using the same principle. `dynamic firstItem = (contentItems as IEnumerable).First();` – Shaun Luttin Aug 08 '14 at 00:35
  • 1
    Casting is a much better answer, yes. – Bertrand Le Roy Aug 08 '14 at 07:04
  • @ShaunLuttin A cast like that will work as long as the T in the `IEnumerable` is a reference type. Also why is ContentItems dynamic then? Why not make it a `IEnumerable`? – Mike Zboray Aug 08 '14 at 09:32
  • @mikez Honestly, I don't know why `contentItems` is dynamic. Also, I don't know what you mean by making `contentItems` an `IEnumerable` - it's returned to me by an API over which I don't have control, so I don't have the ability to change its type. – Shaun Luttin Aug 12 '14 at 16:26
  • @ShaunLuttin If you can't change it, you can't change it. Normally in an MVC view you can declare your model type, but I don't know how it is integrated with Orchard. – Mike Zboray Aug 12 '14 at 16:44