Jan_V
Jan_V

Reputation: 4406

Passing an anonymous type to IComparer<T>

I want to compare my collection of viewmodels based on 2 properties which reside within the viewmodel. What I need is to sort my viewmodels based on the startdate, but if the enddate is lower as today, it should get placed at the bottom of the collection Example on how it should be after the ordering has been fullfilled:

Stardate    Enddate    
25/06/2012  25/06/2022    
21/06/2012  21/04/2018    
31/06/2012  02/07/2012    
28/06/2012  01/07/2012

I think this should be called, something like this:

bankPolicyViewModels.OrderBy(vm => new {StartDate = vm.BankAccountViewModel.StartDateIRA, 
                                        EndDate = vm.BankAccountViewModel.EndDateIRA},
                                        new ComparerForAnonymousType);

But I can't figure out how to define the comparer. At the moment I've only got this:

public class ComparerForAnonymousType<T> : IComparer<T>
        where T : class
{
    public int Compare(T x, T y)
    {
        throw new NotImplementedException();
    }
}

I can try to resolve the defined properties via reflection, but that would be the easy way out (also performance heavy I guess).

Is there some way to define an anonymous type as T, or is there some other way I can sort the collection based on 2 properties?

Upvotes: 1

Views: 917

Answers (4)

Jon Skeet
Jon Skeet

Reputation: 1502406

You can do it via a dummy template value and type inference. You'll need a non-generic class with a generic method though.

You might want to look at ProjectionComparer in MiscUtil which implements all of this. So for example:

var dummy = new { StartDate = default(DateTime),
                  EndDate = default(DateTime) };
var now = DateTime.Now;
var comparer = ProjectionComparer.Create(dummy, x => x.EndDate >= now)
                                 .ThenBy(x => x.StartDate);

On the other hand, as you're already using LINQ, it probably makes more sense to use OrderBy(x => x.StartDate).ThenBy(x => x.EndDate) to start with...

var now = DateTime.Now;
var ordered = bankPolicyViewModels.OrderBy(vm => vm.EndDate >= now)
                                  .ThenBy(vm => vm.StartDate);

(Note that I can't remember the ordering of false/true offhand - you may need to reverse the comparison for EndDate.)

Upvotes: 3

Riccardo
Riccardo

Reputation: 1520

You can implement interface IComparable<T> inside BankAccountViewModel class and in this way you can use all properties of the class. Or indicates the base BankAccountViewModel class inheritance constraint of interface IComparer<T>.

Upvotes: 0

Iridium
Iridium

Reputation: 23731

To put all the items with EndDate < today at the bottom, then sort everything by StartDate you could use:

var today = DateTime.Today;
bankPolicyViewModels
    .OrderBy(vm => vm.BankAccountViewModel.EndDateIRA < today ? 1 : 0);
    .ThenBy(vm => vm.BankAccountViewModel.StartDateIRA);

Upvotes: 2

jlew
jlew

Reputation: 10601

Make both view models implement an interface that defines the properties being compared, and then make the comparer operate on that interface.

Upvotes: 0

Related Questions