我正在考虑创建自己的序列化程序,我需要一种简单的方法来为给定的.NET类型编写属性访问者,以便获取每个属性(包括嵌套属性)的属性。
似乎最简单的方法是从DFS或BFS的迭代版本开始遍历所有属性,所以我开始编写以下代码:
public static class Algorithms
{
public static IEnumerable<TNode> DfsIterativeTraverse<TNode>(this TNode node, Func<TNode, IEnumerable<TNode>> childNodeSelectors)
{
if (node == null)
{
yield break;
}
var stack = new Stack<TNode>();
stack.Push(node);
while (stack.Any())
{
var top = stack.Pop();
foreach (var child in childNodeSelectors(top))
{
stack.Push(child);
}
yield return top;
}
}
public static IEnumerable<TNode> BfsIterativeTraverse<TNode>(this TNode node, Func<TNode, IEnumerable<TNode>> childNodeSelectors)
{
if (node == null)
{
yield break;
}
var queue = new Queue<TNode>();
queue.Enqueue(node);
while (queue.Any())
{
var front = queue.Dequeue();
foreach (var child in childNodeSelectors(front))
{
queue.Enqueue(child);
}
yield return front;
}
}
}
然后将其应用于某些匿名类以获取不同的属性:
public static class Program
{
public static void Main(params string[] args)
{
var stuff = new
{
A1 = new
{
B1 = new
{
D1 = 42
},
C1 = new
{
E1 = "Hello"
}
},
A2 = new
{
B2 = new
{
D2 = 42
},
C2 = new
{
E2 = "Hello"
}
}
};
var properties = stuff.GetType().GetProperties();
foreach (var property in properties)
{
var childProperties = property.DfsIterativeTraverse(x =>
{
if (x.PropertyType.IsPrimitive|| x.PropertyType == typeof(string))
{
return Enumerable.Empty<PropertyInfo>();
}
return x.PropertyType.GetProperties();
});
var count = 0;
foreach (var childProperty in childProperties)
{
Console.WriteLine($"{$"\t".Repeat(count)}{childProperty.Name}: {childProperty.PropertyType.Name}");
count++;
}
}
Console.ReadKey();
}
}
public static class StringExtensions
{
public static string Repeat(this string source, int count)
{
var stringBuilder = new StringBuilder(source.Length * count);
for (var i = 0; i < count; i++)
{
stringBuilder.Append(source);
}
return stringBuilder.ToString();
}
}
但这段代码返回:
A1: <>f__AnonymousType1`2
C1: <>f__AnonymousType3`1
E1: String
B1: <>f__AnonymousType2`1
D1: Int32
A2: <>f__AnonymousType4`2
C2: <>f__AnonymousType6`1
E2: String
B2: <>f__AnonymousType5`1
D2: Int32
我考虑过增加一个计数,这个计数会递增,但结果并不是那么简单。