简体   繁体   中英

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

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM