我使用以下方法递归遍历对象的属性:
void GetProps(object obj)
{
if (obj == null)
return;
var objType = obj.GetType();
var properties = objType.GetProperties();
foreach (var property in properties)
{
object value = property.GetValue(obj, null);
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
var enumerable = (IEnumerable)value;
foreach (object child in enumerable)
GetProps(child);
}
else
{
GetProps(value);
}
}
}
对象非常复杂(超过30个类)。在StackOverflowException
处深入对象时,我得到了GetProps(value
。
有没有一种方法可以捕获异常并检查异常原因,并解决问题?
编辑
我在方法顶部添加了一个故障保护:
if (visited.Contains(obj))
return;
visited.Add(obj);
问题不在于循环引用(我没有),而在于诸如DateTime
,int
和decimal
之类的属性类型。假设它们是原始的,但是IsPrimitive
属性是false
。
我可以区分这些类型和自己的类吗?
答案 0 :(得分:4)
A StackOverflowException
can't be caught,除非您扔了它,因为它表明您的应用程序存在致命问题。
最有可能发生这种情况是因为您有一个循环引用。即一个包含另一个对象的对象,该对象包含对原始对象的引用。两个类之间可以有任意数量的层次结构级别。
您需要实现某种机制来停止遍历您已经遍历的对象,例如借助哈希集。
答案 1 :(得分:0)
以下是不使用递归的示例,该示例利用了Eric Lippert的explicit stack approach。我不知道字符串的行为是否符合您的预期,但这可能会阻止堆栈崩溃:
public static IEnumerable<object> GetPropertiesDepthFirst(object obj)
{
if (obj == null)
yield break;
var stack = new Stack<object>();
stack.Push(obj);
while (stack.Count > 0)
{
var current = stack.Pop();
yield return current;
var objType = current.GetType();
var properties = objType.GetProperties();
foreach (var property in properties)
{
object value = property.GetValue(current, null);
if (value == null)
continue;
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
var enumerable = (IEnumerable)value;
foreach (object child in enumerable)
stack.Push(child);
}
else
{
yield return value;
}
}
}
}
对于具有已定义索引的IEnumerables,您可能还希望排除索引属性:
objType.GetProperties().Where(p => p.GetIndexParameters().Length == 0)