Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a list of property names in a class in certain a order

Tags:

c#

I have a class similar to:

public class MyClass : MyBaseClass
{
        public string Field1 { get; set; }
        public string Field2 { get; set; }
        public string Field3 { get; set; }
        public string Field4 { get; set; }
}

public class MyBaseClass
{
        public string BaseField1 { get; set; }
        public string BaseField2 { get; set; }
        public string BaseField3 { get; set; }
        public string BaseField4 { get; set; }
}

I then created a method to pull the names from the class.

private void MyMethod<T>(List<T> listData) where T : class
{
    String[] fieldNames = Array.ConvertAll<PropertyInfo, String>(typeof(T).GetProperties(), delegate(PropertyInfo fo) { return fo.Name; });

    // Do something with the fieldNames array....
}

So when I get my array it would be in the following order:

Field1
Field2
Field3
Field4
BaseField1
BaseField2
BaseField3
BaseField4

I was wondering if it was possible to change the order so that the base class fields were first followed by the derived class fields?

like image 642
John Doe Avatar asked May 10 '17 13:05

John Doe


1 Answers

Let's implement a simple method to get how deep is the class in the class hierarchy

null <- object <- ... <- MyBaseClass <- MyClass <- ...

Implementation

// 0     - null
// 1     - object
// ...
// n     - MyBaseClass
// n + 1 - MyClass
// ...
private static int TypeLevel(Type type) {
  if (null == type)
    return 0;

  return TypeLevel(type.BaseType) + 1;
}

And then with a help of Linq sort by this criterium, the only little trick is to use DeclaringType - where (in which class) the property has been declared:

// fieldNames are actually properties' names
string[] fieldNames = typeof(MyClass)
  .GetProperties()
  .OrderBy(p => TypeLevel(p.DeclaringType)) // <- base first, derived last
  .ThenBy(p => p.Name) // <- let's organize properties within each class
  .Select(p => p.Name) 
  .ToArray();

Console.Write(string.Join(Environment.NewLine, fieldNames));

Outcome:

BaseField1
BaseField2
BaseField3
BaseField4
Field1
Field2
Field3
Field4

Finally, your method can be something like this:

// we don't want any restictions like "where T : class"
private void MyMethod<T>(List<T> listData) {
  ...
  string[] fieldNames = typeof(T)
    .GetProperties()
    .OrderBy(p => TypeLevel(p.DeclaringType)) // <- base first, derived last
    .ThenBy(p => p.Name) // <- let's organize properties within each class
    .Select(p => p.Name)
    .ToArray();

  ...
}
like image 159
Dmitry Bychenko Avatar answered Oct 26 '22 00:10

Dmitry Bychenko