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



我有一个具有嵌套属性的类,类似于以下内容:

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

其中

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

我需要开发一个通用方法,它可以接受任何类文件,并列出所有这些层中的所有属性及其值。在本例中,可能存在与共享文件一样复杂的文件或更多文件!

我已经使用反射和LINQ查询来计算这些属性的名称,但最多只能获得2层的这些信息,并且无法识别可能是另一类类型的属性,也无法获得其相应的属性。

我希望保留广泛的循环/递归作为最后一种方法,但更喜欢LINQ解决方案,因为无论复杂性如何,这都必须在一分钟内处理完毕。

我需要一个具有所有这些属性的对象列表作为响应。这是用于PII数据清理

我似乎已经用尽了所有的选择,很想听听你对此的解决方案。

非常感谢!

使用我的库中的一些扩展方法,并假设您只需要属性而不需要字段,您可以编写一个路由来排队工作对象并处理队列。这会输出以类路径为前缀的属性,但您只能使用底部的属性名称。

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

注意:如果您喜欢不同顺序的输出,可以对ans进行排序,例如返回ans.OrderBy(t => t.Item1).ToList()

以下是使用的扩展方法:

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

最新更新