-2

If I use this next bellow code in C# using Unity, I get a IEnumerable<widget> back but I want an ObservableCollection<widget> back.

public class widget
{
    public string myString;
    public int myInt;
}

public ObservableCollection<widget> myCollectionOfWidgets;

I can iterate through the collection with ForEach with no problem. I even implemented IComparable for my widget so that I can sort them with myInt property.

But when I try to get the first 15 items in the collection ordered by myInts in descendingOrder, I get an IEnumerable back:

var newWidgetCollection = myCollectionOfWidgets.OrderByDescending(myCollectionOfWidgets => myCollectionOfWidgets.myInts).Take(15);

If I try to cast it back to an ObservableCollection of widgets like so:

var newObservableCollectionOfWidgets = (ObservableCollection<widget>)newWidgetCollection;

I get an error reading this:

"InvalidCastException: Specified cast is not valid."

I would like someone to answer me:

  1. Why does this happen? In other words, I forgot to use an interface, which one?
  2. Maybe point me in the correct direction.
  3. If my code is incorrect, where did I go wrong.
Filburt
  • 17,626
  • 12
  • 64
  • 115

1 Answers1

0

When you use foreach loop and another code that just iterates through the collection you don't neeed to convert items since they are remains the same. But when you are using LINQ ( take or orderby for example), them most LINQ methods returns IEnumerable collection. I don' t mean absolutely all of them since some methods return Max , Min , ... or a single item).

Linq can convert it to List immediately using ToList method. But it doesnt have a method to return and ObservableCollection. Fortunately the obsrvable collection has a special consructor to convert IEnumerable. Try this

ObservableCollection<widget> newWidgetCollection = new ObservableCollection<widget> ( 
myCollectionOfWidgets.OrderByDescending(myCollectionOfWidgets 
=> myCollectionOfWidgets.myInt)
.Take(15)
);

if you want to improve performance by not repeating conversions to Observable, start from the List if it possible, and only after completing all trasformations convert it to Observable.

If you use it often, try this extention

var  newWidgetCollection  =  myCollectionOfWidgets
.OrderByDescending(o =>o.myInt).Take(15)
.ToObservableCollection<widget>();

public static ObservableCollection<T> ToObservableCollection<T>
        (this IEnumerable<T> source)
    {
        if (source == null)
        {
            throw new ArgumentNullException("no source found");
        }
        return new ObservableCollection<T>(source);
    }
Serge
  • 40,935
  • 4
  • 18
  • 45
  • That worked, thanks. But does that mean that all Linq queries returns an IEnumerable back? Is there another way to split (like python) the collection? I want to retain the Observable events. – DragonAngel the Original Dec 10 '21 at 20:26
  • @DragonAngeltheOriginal I updated my answer. – Serge Dec 10 '21 at 21:45
  • "does that mean that all Linq queries returns an IEnumerable back" for those that return a collection, yes - most add a "view" iterator on top of the original collection. If you want an observable collection on the results of a query you'll have to create a _new_ observable and reattach events. – D Stanley Dec 10 '21 at 22:08
  • @DStanley I don' t mean all absolutely since some of them return Max , Min , ... or a single item – Serge Dec 10 '21 at 22:10
  • Which is why I said "for those that return a collection". Though I added that later so you may have missed that edit. – D Stanley Dec 10 '21 at 22:11