如何按特定顺序获取类中属性名称的列表

6

我有一个类似于以下代码的类:

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; }
}

然后我创建了一个方法来从类中提取名称。

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....
}

因此,当我获取我的数组时,它将按以下顺序:

Field1
Field2
Field3
Field4
BaseField1
BaseField2
BaseField3
BaseField4

我想知道是否可能改变顺序,让基类字段排在派生类字段之前?

3个回答

5

让我们实现一个简单的方法来获取类在类层次结构中的深度。

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

实现

// 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;
}

然后通过使用 Linq 按照此标准排序,在这里唯一的小技巧是使用 DeclaringType - 属性在哪个类中被声明:

// 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));

输出结果:

BaseField1
BaseField2
BaseField3
BaseField4
Field1
Field2
Field3
Field4

最后,您的方法可以像这样:
// 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();

  ...
}

0
您需要编写类似以下代码来遍历类层次结构,然后获取属性。
static void GetProperties(Type type, List<string> returnValue) {
    var props = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
    returnValue.AddRange(props.Select(p => p.Name).OrderBy(p => p));
}

private void MyMethod<T>(List<T> listData) where T : class {
    var type = typeof(T);
    List<string> properties = new List<string>();
    while (type != null) {
        GetProperties(type, properties);
        type = type.BaseType;
    }
}

与其让一个方法接受一个List并对其进行改变,不如让它只返回它正在计算的项目。如果调用者想将它们添加到列表中或进行其他任何操作,他们可以自行处理。 - Servy

-1

选择基类的所有属性并与派生类的所有属性合并。使用Distinct()方法可以删除所有重复项。如果需要更多复杂性,您可以尝试@Vikhram的解决方案。

        var properties = typeof(MyBaseClass).GetProperties().Select(x => x.Name)
            .Union(typeof(MyClass).GetProperties().Select(x => x.Name)).Distinct();

这如何按照请求的特定顺序提供属性? - Michael McGriff
所请求的顺序是:先是基类属性,然后是派生类。代码确保了这个顺序。 - MiGro
该方法是通用的;它不是针对编译时已知的特定类型和同样在编译时已知的基类进行硬编码的。 - Servy
谢谢。我已经忽略了那个事实。 - MiGro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接