Click here to Skip to main content
15,881,803 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Background to problem: I have a
C#
BindingList<T>
of dynamic objects. These objects are of some type of class which is created at runtime. This class can have 1 or 2 or 3 or more properties. Names of these properties can also be different everytime when this class is created.
e.g.
VB
Class Data
{
Property Value1;
Property Value2;
Property Value3;
..
...
}


Next time this class can be
VB
Class Data
{
Property Value1;
Property Value2;
}


Issue is: Based on some parameter I can get a value from user 'Value1'. Then I want to sort this list of dynamic objects on value of property 'Value1'.
Posted

1 solution

You need to implement a Comparer[^], and pass it to the List.Sort[^] method.
But since you have dynamic objects, you need to use reflection to get the values. Use this[^] approach:

C#
public class DynamicSerializableComparer : IComparer<object>
{
    string _property;

    public DynamicSerializableComparer(string property)
    {
        _property = property;
    }

    public int Compare(object stringA, object stringB)
    {
        string valueA = stringA.GetType().GetProperty(_property).GetValue();
        string valueB = stringB.GetType().GetProperty(_property).GetValue();

        return String.Compare(valueA, valueB);
    }

}

Of course, if the property you have is not string or not comparable as string, you should change the last statement accordingly.

[Update: some improvements, and a sample]
As I mentioned, you can't use OrderBy, since there is no property you can specify in the lambda expression.

C#
public class DynamicSerializableComparer : IComparer<object>
{
    string _property;

    public DynamicSerializableComparer(string property)
    {
        _property = property;
    }

    public int Compare(object stringA, object stringB)
    {
        string valueA = (string)stringA.GetType().GetProperty(_property).GetValue(stringA, null);
        string valueB = (string)stringB.GetType().GetProperty(_property).GetValue(stringB, null);

        return String.Compare(valueA, valueB);
    }
}

void Main()
{
    var a1 = new { id = 1, name="Peter", email="a@x.com"};
    var a2 = new { id = 2, name="John", address="USA"};
    var a3 = new { id = 3, name="Robert", address="France"};
    var a4 = new { id = 4, name="Albert", position="Boss"};

    var a = new List<object> {a1, a2, a3, a4};

    a.Sort(new DynamicSerializableComparer("name"));

    a.Dump();
}


This sample will run directly in LinqPad[^] (I suggest you download it if you don't have it already, it is a must if you develop linq stuff...), but you can write a simple dumper or inspect the sorted list in VS. As you can see, there is not even a class defined, all objects are inline. Won't work if you change the constructor parameter to a property that's not common in all objects - in such case you have to decide and add logic to the comparer how to compare nonexistent properties. But you can use this sample to implement a comparer for your needs.
 
Share this answer
 
v3
Comments
Versatile49 24-Jan-13 3:53am    
I ge ta complie time error: The type arguments for method 'System.Linq.Enumerable.OrderBy<tsource,tkey>(System.Collections.Generic.IEnumerable<tsource>, System.Func<tsource,tkey>, System.Collections.Generic.IComparer<tkey>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Maybe this is because of the dynamic class that I am creating at runtime
Zoltán Zörgő 24-Jan-13 12:38pm    
No. OrderBy makes no sense in this context, since you can not reference a dynamic property at compile time in the lambda expression. You have to use Sort. I will post a more complex sample shortly.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900