Search code examples
c#genericscontainersselection-sortgetproperty

sorting a generic list from within a generic container class


I need to sort a list by any one of its properties, but i dont know which of these properties it will specifically be sorted on. The Main method below.

  static void Main(string[] args)
    {
        Things<Something> something = new Things<Something>();
        something.Add(new Something 
                        { Thing = "Apartment", Price = 1500000 });
        something.Add(new Something
                        { Thing = "Bed", Price = 10000 });
        something.Add(new Something 
                        { Thing = "Lamp", Price = 600 });
        something.Add(new Something 
                        { Thing = "Car", Price = 5000000 });

        Console.WriteLine("\n\tStuff sorted by description");
        something = something.SelectionSort("Thing");
        foreach (Something thing in something)
            Console.WriteLine("\t" + thing);

        Console.WriteLine("\n\tStock items sorted by value");
        something = something.SelectionSort("Value");
        foreach (Something thing in something)
            Console.WriteLine("\t" + thing);

        Console.Write("\n\tPress any key to exit ...");
        Console.ReadKey();
    } 

I have a struct

  public struct Something
 {
  public string Thing { get; set; }
  public decimal Price { get; set; }
 }

And a generic container class called things

     public class Things<T> : IEnumerable<T>
{
    
    private List<T> lstItems;
    public int Count { get { return lstItems.Count; } }


    public Things() { lstItems = new List<T>(); }
    public Things(List<T> items_) { lstItems = new List<T>(items_); }

    public void Add(T item)
    {
        lstItems.Add(item);
    }

    
    public T this[int i]
    {
        get { return lstItems[i]; }
        set { lstItems[i] = value; }
    }
    
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new System.NotImplementedException();
    }

    public IEnumerator<T> GetEnumerator()
    {
        foreach (T item in lstItems)
            yield return item;
    }  
}

An extensions class extends the generic container class

 public static class ExtensionsClass
{
    private static string SortFiield { get; set; }

    private static object GetProperty<T>(T thing, string nameofProp)
    {
        return thing.GetType().GetProperty(nameofProp).GetValue(thing, null);
    }

    private static int Compare<T>(T x, T y)
    {
        IComparable propX = (IComparable)GetProperty(x, SortFiield);
        IComparable propY = (IComparable)GetProperty(y, SortFiield);
        return propX.CompareTo(propY);
    }

    public static Things<T> SelectionSort<T>(this Things<T> things, string SORTFIELD)
    {
        List<T> lsstt = new List<T>(things);
        int iIndex;
        T temporary;
        SortFiield = SORTFIELD;
        for (int i = 0; i < lsstt.Count - 1; i++)
        {
            iIndex = i;
            for (int j = i + 1; j < lsstt.Count; j++)
            {
                string first = GetProperty(lsstt[j], SortFiield).ToString();
                string second = GetProperty(lsstt[iIndex], SortFiield).ToString();

                if (Compare(first, second) < 0)
                    iIndex = j;
            }
            temporary = lsstt[i];
            lsstt[i] = lsstt[iIndex];
            lsstt[iIndex] = temporary;
        }
        return new Things<T>(lsstt);
    }
}  

The problem i am encountering is that get property in the extension class returns null, but i know that the object i am trying to return exists. It is found by the "String first = ...." line but when getproperty is called from the Compare method then it returns null.


Solution

  • You are passing "first", "second" to Compare. In your case both of them are strings and not objects, you need to pass "lsstt[j]" and "lsstt[iIndex]" to it.

    if (Compare(lsstt[j], lsstt[iIndex]) < 0)
        iIndex = j;