0

我在寻找一种简单的方法来查找Reflection对象上使用的所有字符串值时遇到了一些问题。

我需要递归地扫描一个对象,包括任何列表、数组以查找与值匹配的字符串。到目前为止,我正在尝试返回所有值的列表,然后我可以检查该列表,但是我遇到了一个问题,StackOverflowException如果对象包含任何循环依赖项,这可能会引发 a。

到目前为止我所拥有的:(我知道,我知道,但它正在进行中:))

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

1 回答 1

4
  1. 任何列表,任何数组 -> 任何 IEnumerable。所以你可以替换:

    if (type.IsArray)
    

    至:

    if (typeof(IEnumerable).IsAssignableFrom(type))
    
  2. 为了防止StackOverflowException只是不访问访问过的对象。你喜欢想法吗?所以,首先我们必须选择:我们不想访问所有访问过的对象或只访问父对象。在这种情况下,我们不会访问所有访问过的对象。所以,修改标题:

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

    小心,如果你想从不同的对象中看到相同的字符串,你必须防止将字符串添加到访问的对象列表中。为什么?字符串实习。像这样:

    if (!(obj is string))
        visitedObjects.Add(obj);
    

经过一些代码格式化后,我得到了这个:code

于 2013-07-08T08:20:06.177 回答