Question

class Employee
{
    public string Name {get;set;}
    public int employee_id {get;set}
    public int Age {get;set}
}

Class EmployeeCollection : IEnumerable, IEnumerable<Employee>, IOrderedEnumerable<Employee>
{
    public Expression<Func<Employee, dynamic>> SortOrder {get;set;}
    protected Dictionary<int,Employee> EmployeeById = new Dictionary<int,Employee>();
    public void AddEmployee(Employee ePassed)
    {
        EmployeeById[ePassed.employee_id] = ePassed;
    }
    public IEnumerator<Employee> GetEnumerator()
    {
      foreach (int id in EmployeeByID.Keys)
      {
        yield return EmployeeById[id];
      }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
      return this.GetEnumerator();
    }
    public IOrderedEnumerable<Employee> CreateOrderedEnumerable<TKey>(Func<Employee, TKey> KeySelector, IComparer<TKey> comparer, bool descending)
    {
      if (descending)
          return this.OrderByDescending(KeySelector, comparer);
      else
          return this.OrderBy(KeySelector, comparer);
    }
    public IEnumerable<Employee> OrderedObjects
    {
        if (this.SortOrder == null)
            return (IEnumerable<Employee>)this;  // No Sort Order applied
        else
        {
          // How do I get the "parameters" from SortOrder to pass into CreateOrderedEnumerable?
          throw new NotImplementedException();
        }
    }
}

I want to be able to use syntax similar to the following...

EmployeeCollection.SortOrder = (x => x.Name);
foreach (Employee e in EmployeeCollection.OrderedObjects)
{
  // Do something in the selected order
}

There are thousands of examples of how to throw sorted, filtered, etc results into a new List, Collection, ObservableCollection, etc. but if your existing collection already responds to events, automatically adds new objects in response to notifications, user actions, new data coming in from server, etc then all that functionality is either "lost" or has to be "added" to make the new List, Collection, ObservableCollection, etc. listen to the original collection in order to somehow stay in sync with all of the various updates, properties, etc that the original Collection ALREADY KNOWS ABOUT and handles... I want to be able to have the ORIGINAL "EmployeeCollection" simply dish out the "Employee" objects in the requested SortOrder...

I made a "wild ass guess" about the syntax for the "SortOrder" property based on wanting to make the syntax of the SortOrder property similar to the orderby portion of lambda expressions that other developers on the team are used to working with by looking at the extension methods in System.Linq.Enumerable similar to the following: public static IOrderedEnumerable<TSource> OrderBy<ToSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

I am new to Linq, lambda, etc and apologize in advance if I somehow missed some key aspect of Linq/Expression Trees,Predicates,anonymous delegates, etc that others consider obvious.

Was it helpful?

Solution

This works when you don't use ThenBy-type operations (which are all the IOrderedEnumerable<T> interface really adds). See C#: How to implement IOrderedEnumerable<T> for a solution to support that.

public class Employee
{
    public string Name {get;set;}
    public int employee_id {get;set;}
    public int Age {get;set;}
}

public class EmployeeCollection : IEnumerable, IEnumerable<Employee>, IOrderedEnumerable<Employee>
{
    public Func<Employee, object> SortOrder {get;set;}
    public Func<Employee, bool> Filter {get;set;}
    protected Dictionary<int,Employee> EmployeeById = new Dictionary<int,Employee>();
    public void Add(Employee ePassed)
    {
        EmployeeById[ePassed.employee_id] = ePassed;
    }
    public IEnumerator<Employee> GetEnumerator()
    {
        var employees = EmployeeById.Keys.Select(id => this.GetEmployee(id));
        if (Filter != null)
            employees = employees.Where(Filter);
        if (SortOrder != null)
            employees = employees.OrderBy(SortOrder);
        return employees.GetEnumerator();
    }
    public Employee GetEmployee(int id)
    {
        return EmployeeById[id];
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
      return this.GetEnumerator();
    }
    public IOrderedEnumerable<Employee> CreateOrderedEnumerable<TKey>(Func<Employee, TKey> KeySelector, IComparer<TKey> comparer, bool descending)
    {
      throw new NotImplementedException();
    }
}

// this is some code you might use to test this:
var EmployeeCollection = new EmployeeCollection
{
    new Employee { employee_id = 1, Age = 20, Name = "Joe" },
    new Employee { employee_id = 2, Age = 30, Name = "Thomas" },
    new Employee { employee_id = 3, Age = 25, Name = "Robert" },
};
EmployeeCollection.SortOrder = x => x.Age;
EmployeeCollection.Filter = x => x.Name.Length > 4;
foreach (Employee e in EmployeeCollection)
{
    // do something
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top