Sorting a List<> of complex type by Name property

tinstaafl 0 Tallied Votes 295 Views Share

I'm working on a project that contains 3 different lists. 2 lists of 2 different controls, and 1 list of a custom class. I found that I needed each of these lists sorted. The problem with sorting a list of complex types is there's no default comparer for them. That means using a custom routine to sort by a specific property. Probably the most common property that will have a unique value to each member is the 'Name' property. Instead of having 3 different sort routines to sort by the 'Name' property, I wanted to come up with a generic routine that would sort a list of any object that has a 'Name' property. I tried investigating other solutions, but I found them to be quite complicated, probably because I haven't learned Lambda yet. Thus the accompanying very simple code. The problem I faced was getting the name string when the generic Object type doesn't have a 'Name' property. I found that for the custom class I had to set up 'Name' as a property, I used the Auto-Implented Property({ get; set; }). I haven't tried this with other collections but it should work with any collection that is made up of a type with a 'Name' property and has a Sort() method, that uses IComparer<T>. I haven't tried it yet, but I don't see any reason why this wouldn't work for VB as well.

public static int SortObjectsByName(Object A, Object B)
        {
            return A.GetType().GetProperty("Name").GetValue(A,null).ToString().CompareTo(B.GetType().GetProperty("Name").GetValue(B,null).ToString());
        }
Ketsuekiame 860 Master Poster Featured Poster

Personally, I think it would be better if you created an IComparer<T> for the custom class rather than using reflection this way.

Alternatively, you could create a "SortByName" comparison method, which is similar to what you've done here, however, you'd use generics and constrain it with an interface.

In my opinion, your code is a bit like using a sledgehammer to hang a picture, but that's just me :)

Here's an example of things I might try...

namespace ScratchPad
{
    public interface IName
    {
        string Name {get;}
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<TestClass> classes = new List<TestClass>();
            for (int i = 0; i < 100; i++)
            {
                classes.Add(new TestClass(i));
            }

            // By Comparison Method
            classes.Sort(new Comparison<TestClass>(SortByName));

            // By LINQ
            classes = classes.OrderBy(a => a.Name).ToList();

            foreach (TestClass theClass in classes)
                Console.WriteLine(theClass.Name);

            Console.ReadLine();
        }

        static int SortByName<T>(T first, T second) where T : IName
        {
            return first.Name.CompareTo(second.Name);
        }
    }
}

Your way is good if you want to Sort generic objects that have a Name property and you don't know what these objects might be. However, if you remove the property, your method is broken and you won't know/remember until RunTime (One of the downsides of reflection)

A better design practice would be to interface your objects and then perform sorts based on those, or, use LINQ/Lambda :)

Disclaimer: I don't hate reflection, in fact I use it quite a lot, but it can become nightmarishly complex and fragile ;)

tinstaafl 1,176 Posting Maven

As I mentioned I have 0 experience with Lambda, also I've 0 experience with intefaces. It might not seem as elegant but it does work across different object types, doesn't require learning a new instruction set, or how to code something a person might not be very familiar with, which you might forget next time you need it and have to re-learn. I chose the 'Name' property because it's not likely to be removed once it's there, and it'll work for most intrinsic objects, that I've seen. Also when you're calling it, you only have to remember whether the type has a name property, everything else is automatic, with no special parameters or syntax. It seems very simple when someone with experience can show you. But going through that learning curve for something relatively simple can be daunting.

Ketsuekiame 860 Master Poster Featured Poster

I have concern with regards to your comment saying you have zero experience with interfaces; these are a massive part of Object-Oriented Programming and good design concept. As a friendly suggestion, you really should read up on them as they will be vital to future development and possibly any career you make in programming :)

Your other comment is perfectly valid, although I balk at you saying yours is easier; Reflection can be as, or more, daunting than LINQ to the untrained eye. It looks unwieldly and debugging it will be all but impossible (single line of execution for multiple operations that are reflected). There are also performance implications from reptitively using un-cached reflection.

All the methods here are perfectly valid and your method will do exactly as you say. I just wanted to post a more friendly and visible approach as an optional alternative. I am neither trying to insult nor belittle you.

In programming you should always try and stay ahead of the game and learn new ways of doing things. Although I appreciate that some things can seem daunting, learning how it works and what it does will be of benefit in the long run.

If you still don't understand, that's why this site is here :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.