0

I'm having some issues refactoring and ordering a list.

I have a class called DomainCollection which inherits from KeyedCollection.

public class DomainCollection<T> : KeyedCollection<ID, T>, IDomainCollection<T> where T : class, IDomainObject

I created and filled a list called orders.

var orders = new DomainCollection<Order>();

An order contains an OrderType which contains its own OrderTypes. So if we were to have a condition where we can perform some actions, it would look like this

if(order.Type.Type.Equals(OrderTypes.InvestmentToBankY))
{
  //Currently: logic where it creates a new list and adds the list to the existing order 
  //list and the very end. 
}

Onto my problem. I would like to be able to sort my order list so that my orders with InvestmentToBankY will be either at the bottom or top of my DomainCollection.

Kyuzo
  • 21
  • 1
  • 8
  • `orders.OrderBy(o => o.Type.Type.Equals(OrderTypes.InvestmentToBankY))`? – 41686d6564 stands w. Palestine Oct 05 '22 at 13:33
  • 1
    There's nothing in a `KeyedCollection` to sort the collection itself. You'd have to provide the functionality to sort in place yourself or else call `OrderBy` on the collection as you enumerate it. You could also call `ToArray` or `ToList` and then use the inbuilt functionality of the result to sort that, which would not affect the original collection. – jmcilhinney Oct 05 '22 at 13:33
  • @41686d6564standsw.Palestine I tried that. – Kyuzo Oct 05 '22 at 13:43
  • @Kyuzo `OrderBy` _returns_ an enumerable whose elements are ordered. It does _not_ sort the collection in place. Anyway, I posted an answer below with additional options. – 41686d6564 stands w. Palestine Oct 05 '22 at 14:43

1 Answers1

1

If you just want to iterate over the elements having orders with InvestmentToBankY at the top, you can just use something like:

// Add .ToList() if you want to materialize the items immediately.
var orderedOrders = 
    orders.OrderBy(o => o.Type.Type.Equals(OrderTypes.InvestmentToBankY));
foreach (var order in orderedOrders)
{
    // This will follow the desired order.
}

If you want to end up with a sorted DomainCollection, a not-so-efficient way to do so would be to reconstruct the DomainCollection using the new order. Something like the following should work:

public class DomainCollection<T> : KeyedCollection<ID, T>, IDomainCollection<T> 
    where T : class, IDomainObject
{
    public DomainCollection() { }

    public DomainCollection(IEnumerable<T> items)
    {
        foreach (var item in items)
            this.Add(item);
    }

    protected override ID GetKeyForItem(T item)
    {
        // TODO: implement GetKeyForItem.
        throw new NotImplementedException();
    }
}

Then, you can use it as follows:

var orderedOrders = 
    orders.OrderBy(o => o.Type.Type.Equals(OrderTypes.InvestmentToBankY));

orders = new DomainCollection(orderedOrders);

A better solution that avoids creating a new collection is to rely on the fact that KeyedCollection inherits Collection<T> whose Items property is internally a List<T> and write our own sorting method that uses either a Comparison<T> or an IComparer<T> and calls the corresponding List<T>.Sort overload. Here's an example of the latter:

public class DomainCollection<T> : KeyedCollection<ID, T>, IDomainCollection<T> 
    where T : class, IDomainObject
{
    protected override ID GetKeyForItem(T item)
    {
        // TODO: implement GetKeyForItem.
        throw new NotImplementedException();
    }

    public void Sort(IComparer<T> comparer)
    {
        ((List<T>)this.Items).Sort(comparer);
    }
}

public class OrderComparer : IComparer<Order>
{
    public int Compare(Order x, Order y)
    {
        return x.Type.Type.Equals(OrderTypes.InvestmentToBankY).
            CompareTo(y.Type.Type.Equals(OrderTypes.InvestmentToBankY));
    }
}

Usage:

orders.Sort(new OrderComparer());