我遇到一些问题,找到一种在对象上使用Reflection
查找所有字符串值的简单方法。
我需要递归扫描一个对象,包括任何列表,一个匹配值的字符串数组。
到目前为止,我正在尝试返回所有值的列表,然后我可以检查该列表,但是我遇到了一个问题,如果对象包含任何循环依赖项,这会抛出StackOverflowException
。
到目前为止我所拥有的:(我知道,我知道,但这是一项正在进行的工作:))
private IEnumerable<string> FindStringValues(object obj)
{
if (obj != null)
{
Type type = obj.GetType();
if (type == typeof(string))
{
yield return (string)obj;
}
else if (type.IsArray)
{
var array = obj as Array;
foreach (var item in array)
{
foreach (var str in FindStringValues(item))
{
yield return str;
}
}
}
else if (type.IsClass)
{
FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
foreach (var str in FindStringValues(fieldValue))
{
yield return str;
}
}
}
}
}
所以我正试图找到一种方法让这个StackOverflowException
安全,如果有人可以帮我解决如何找到bool
如果找到匹配的nsinreal
则更好提供的价值。
感谢public static bool FindStringValue(object obj, string valueToFind)
{
return FindStringValue(obj, valueToFind, new List<object>());
}
private static bool FindStringValue(object obj, string valueToFind, IList<object> visitedObjects)
{
if (obj == null && !visitedObjects.Any(item => Object.ReferenceEquals(item, obj)))
{
if (!(obj is string))
{
visitedObjects.Add(obj);
}
Type type = obj.GetType();
if (type == typeof(string))
{
return (obj).ToString() == valueToFind;
}
if (typeof(IEnumerable).IsAssignableFrom(type))
{
var array = obj as IEnumerable;
foreach (var item in array)
{
if (FindStringValue(item, valueToFind, visitedObjects))
{
return true;
}
}
return false;
}
if (type.IsClass)
{
FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object item = field.GetValue(obj);
if (item == null)
continue;
if (FindStringValue(item, valueToFind, visitedObjects))
{
return true;
}
}
}
}
return false;
}
的回答,我能够完成目标:)以下添加,对其他人有帮助
{{1}}
答案 0 :(得分:4)
任何列表,任何数组 - &gt;任何IEnumerable。所以你可以替换:
if (type.IsArray)
要:
if (typeof(IEnumerable).IsAssignableFrom(type))
要防止StackOverflowException
,请不要访问被访问对象。你喜欢这个主意吗?因此,首先我们必须选择:我们不希望访问所有访问过的对象或只访问父对象。在这种情况下,我们不会访问所有访问过的对象。所以,modifcate标题:
// visitedObjects can changes
private static IEnumerable<string> _FindStringValues(object obj, IList<object> visitedObjects)
现在,在此方法中修改FindStringValues
调用_FindStringValues
的所有调用:
_FindStringValues(item, visitedObjects)
并添加可用的包装方法:
private static IEnumerable<string> FindStringValues(object obj) {
return _FindStringValues(obj, new List<object>());
}
在_FindStringValues
中,您必须将传递给此方法的每个obj
添加到访问对象列表中。
visitedObjects.Add(obj);
但在此之前,您必须检查此对象是否未被访问过。您必须使用Object.ReferenceEquals
:
if (visitedObjects.Any(item => Object.ReferenceEquals(item, obj)))
yield break;
要小心,如果要查看来自不同对象的相等字符串,则必须防止向访问对象列表添加字符串。为什么? String interning。像这样:
if (!(obj is string))
visitedObjects.Add(obj);
经过一些代码格式化后,我得到了这个:code。