There are, as you say, many solutions to this. As always it comes down to making the right tradeoffs (between encapsulation, performance, coding effort, ...) and there is really no single answer that is "the best way" for all scenarios. As long as the field types are IComparable you could implement a "ListSorter" class that could sort any List<T> by any field using reflection. This would require relatively little code and the great benefit is that you do it once and then sort whatever object types you want to. The downside is that it's slow, but that may not be a problem if the collections are small. An interesting possibility is to build on this approach by making a ListSorterFactory class instead; this could use reflection to dynamically generate a ListSorter class for a specific type. It may sound like a very advanced sort of thing, but .NET has actually made this kind of thing relatively easy to do. If you have just one type of collection (and don't mind that this code won't be reusable anytime in the future - a sorter factory is potentially useful in many projects down the line) you can always go for inheriting from List<T> and add sort methods using the built-in Sort function with a predicate that compares the particular field the method sorts by. Since this requires the least code, I'll provide an example, but personally I think the ListSorterFactory is a rather more interesting idea!
public class Item
{
public int Number;
public DateTime Time;
public string Message;
}
public class ItemCollection : List<Item>
{
public void SortByNumber()
{
Sort((Item a, Item b) => a.Number.CompareTo(b.Number));
}
public void SortByTime()
{
Sort((Item a, Item b) => a.Time.CompareTo(b.Time));
}
public void SortByMessage()
{
Sort((Item a, Item b) => a.Message.CompareTo(b.Message));
}
}
However, since the pattern of this code is so regular, why not just generate it instead of writing it manually? Using reflection you can easily find all public fields or properties (or non-public if that's of interest, though you shouldn't do this with private members in any case!) and generating the code is then completely straightforward. And now I realize that dynamically compiling such generated code may not be so meaningful, because you've got no obvious way to *use* that generated code in your non-generated code! (If there was a single interface with many implementations generated code would do the t