c# - 迭代属性和嵌套的第一级属性

标签 c# reflection

<分区>

我有以下类(class)

public class Car
{
    public int CarId { get; set;}
    public string Description { get; set;}
    public Engine Engine { get; set;}
}

public class Engine
{
    public int EngineId { get; set;}
    public int Description { get; set;}
}

现在我想迭代 Car 中的所有属性和 Engine 中的所有属性,我不想硬编码属性名称“Car or Engine”

获取 Car 的所有属性的示例,其中 obj 是 Car 的实例。

var properties = obj.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);

但这不会迭代 Engine 的属性。

最佳答案

FlattenHierarchy 并不像您想象的那样,而是遵循静态成员的继承层次结构。

如果你想获得对象的子属性,你需要自己做:

static IEnumerable<PropertyInfo> FlattenProperties(Type type)
{
    // Assumption #1: you do not want "simple" types enumerated
    if (!type.IsClass)
        return Enumerable.Empty<PropertyInfo>();

    // Assumption #2: you want to ignore "the usual suspects"
    if (type.Namespace != null && type.Namespace.StartsWith("System"))
        return Enumerable.Empty<PropertyInfo>();

    // Assumption #3: your class hierarchy won't destroy recursion
    // Assumption #4: you simply want the PropertyInfo
    return type.GetProperties(BindingFlags.FlattenHierarchy
                            | BindingFlags.Instance
                            | BindingFlags.Public)
               .SelectMany(pi => new[] { pi }
                              .Concat(FlattenProperties(pi.PropertyType)));
}

如果在您 (a) 知道递归的深度,并且 (b) 有办法改变代码的代码中使用它,我建议为这些类型创建一个基类、接口(interface)或属性/属性。

// Replace Assumptions #1 and #2 above with this:
// Assumption #5: given interface ISomething { }
if (!typeof(ISomething).IsAssignableFrom(type))
    return Enumerable.Empty<PropertyInfo>();

如果您需要“属性树”(即假设 #4 不正确):

static IEnumerable<IEnumerable<PropertyInfo>> FlattenProperties(
    Type type,
    IEnumerable<PropertyInfo> ancestors = null)
{
    // change to Assumptions #1/#2 or #5 to yield break
    // ...

    ancestors = ancestors ?? Enumerable.Empty<PropertyInfo>();
    var properties = type.GetProperties(
                          BindingFlags.FlattenHierarchy
                        | BindingFlags.Instance
                        | BindingFlags.Public);
    foreach (var property in properties)
    {
        // again, Assumption #3: your class hierarchy won't destroy recursion
        // Assumption #6: you actually want the initial nested property too
        yield return ancestors.Concat(new[] { property });
        foreach (var nested in FlattenProperties(
            property.PropertyType, 
            ancestors.Concat(new [] { property })))
        {
            yield return nested;
        }
    }
}

在第二种情况下,产生的输出类似于:

// foreach (var tree in FlattenProperties(typeof(Car)))
// {
// Console.WriteLine("{0}", String.Join(".", tree.Select(pi => pi.Name)));
// }
CarId
Description
Engine
Engine.EngineId
Engine.Description

关于c# - 迭代属性和嵌套的第一级属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18600819/

相关文章:

javascript - 寻找更好的方法将反射方法与 Javascript 中的对象附加在一起

java - 如何获取所有实现指定接口(interface)的类

.net - 从 System.__ComObject 基类型调用方法

java - 为什么我无法获取字段的注释?

c# - 为什么不能使用 'as' 运算符来解析不可为空的值类型?

c# - 我可以在没有 http 处理程序的情况下隐藏 asp.net 页面上的图像路径吗?

c# - C# 中的 Catch 和 Catch(异常 e)

c# - 系统.BadImageFormatException : Could not load file or assembly- Exception only on hosting server?

c# - 填充复数数组错误

java、反射、性能等