Home > other >  Creating a LINQ expression to get the correct property at the bottom of a KeyedCollection
Creating a LINQ expression to get the correct property at the bottom of a KeyedCollection

Time:10-06

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.

CodePudding user response:

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());
  • Related