简体   繁体   English

如何获取所有属性的列表,包括类文件中嵌套对象中的属性

[英]How do I get a list of all properties including those within nested objects within a class file

I have a class with nested properties, similar to the following:我有一个具有嵌套属性的类,类似于以下内容:

Class X 
{ 
    public ClassA propA { get; set; }  
    public IEnumerable<ClassB> propB { get; set; }
}

where在哪里

Class A 
{ 
    public IEnumerable<ClassC> prop C { get; set; } 
    public ClassD propD { get; set; } // Enum type
}

Class B 
{ 
    public ClassE propE { get; set; }  
    public string prop1...prop10 { get; set; } 
    public IEnumerable<ClassF> propF { get; set; }
} // and so on

I am required to develop a generic method which can accept any class file and list out all properties along with their values across all these layers.我需要开发一个通用方法,它可以接受任何类文件并列出所有这些层中的所有属性及其值。 There can be files with a complexity as shared in this example or more!可能存在具有本示例中共享的复杂性或更多的文件!

I have used Reflection and LINQ queries to figure the names of these properties but can only get this information for up to 2 layers and have not been able to identify properties which could be of another class type and obtain it's corresponding properties as well.我使用反射和 LINQ 查询来计算这些属性的名称,但最多只能获取 2 层的此信息,并且无法识别可能属于其他类类型的属性并获取其相应的属性。

I would want to keep extensive looping / recursion as the last approach but would rather prefer LINQ solutions as irrespective of the complexity, this would have to be processed in under a minute.我希望将广泛的循环/递归作为最后一种方法,但更喜欢 LINQ 解决方案,因为无论复杂性如何,这都必须在一分钟内处理。

I would need a list of objects with all these properties as a response.我需要一个具有所有这些属性的对象列表作为响应。 This is for PII Data cleansing这是用于 PII 数据清理

I seem to have exhausted all options and would love to hear your solutions to this.我似乎已经用尽了所有选择,很想听听您对此的解决方案。

Many thanks!非常感谢!

Using some extension methods from my library, and assuming you only need properties and not also fields, you can write a routing to queue work objects and process the queue.使用我的库中的一些扩展方法,并假设您只需要属性而不需要字段,您可以编写一个路由来排队工作对象并处理队列。 This outputs the properties prefixed by their path through the classes, but you could only use the property names at the bottom instead.这会输出以它们通过类的路径为前缀的属性,但您只能使用底部的属性名称。

public static class ObjectExt {
    public static List<(string, string)> AllPropsWithValues(this object first) {
        var ans = new List<(string, string)>();

        var workQueue = new Queue<(string, object)>();
        workQueue.Enqueue(("", first));

        while (!workQueue.IsEmpty()) {
            var (objName, workObj) = workQueue.Dequeue();
            if (workObj != null) {
                var workType = workObj.GetType();

                if (workType.IsSimple()) {
                    ans.Add((objName, workObj.ToString()));
                }
                else if (workType.IsIEnumerable()) {
                    var index = 0;
                    foreach (var obj in (IEnumerable)workObj) {
                        workQueue.Enqueue(($"{objName}[{index++}]", obj));
                    }
                }
                else {
                    foreach (var pi in workType.GetProperties()) {
                        workQueue.Enqueue(($"{objName.SuffixNonEmpty(".")}{pi.Name}", pi.GetValue(workObj)));
                    }
                }
            }
        }
        return ans;
    }
}

NOTE: If you prefer the output in a different order, you could sort ans eg by returning ans.OrderBy(t => t.Item1).ToList() .注意:如果您更喜欢不同顺序的输出,您可以通过返回ans.OrderBy(t => t.Item1).ToList()ans进行排序。

These are the extension methods used:这些是使用的扩展方法:

public static class MyExt {
    public static bool IsEmpty<T>(this Queue<T> q) => q.Count == 0;
    public static bool IsNullableType(this Type aType) =>
    // instantiated generic type only
        aType.IsGenericType &&
        !aType.IsGenericTypeDefinition &&
        Object.ReferenceEquals(aType.GetGenericTypeDefinition(), typeof(Nullable<>));
    // from Stack Overflow
    public static bool IsSimple(this Type type) =>
        type.IsNullableType() ? type.GetGenericArguments()[0].IsSimple()
                              : type.IsPrimitive ||
                                type.IsEnum ||
                                type.Equals(typeof(string)) ||
                                type.Equals(typeof(decimal)) ||
                                type.Equals(typeof(TimeSpan)) ||
                                type.Equals(typeof(DateTime));
    public static bool IsIEnumerable(this Type type) => type.GetInterface(nameof(IEnumerable)) != null;
    public static string SuffixNonEmpty(this string s, string after) => String.IsNullOrEmpty(s) ? String.Empty : $"{s}{after}";

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM