【问题标题】:How to enumerate all reachable objects given a root object?如何枚举给定根对象的所有可达对象?
【发布时间】:2012-05-20 21:00:34
【问题描述】:

我想实现一个方法,它接收一个根对象并返回一个列表,其中包含对从根对象开始可以到达的所有对象的引用。它的签名是这样的:

static List<object> EnumerateObjectsInRange(object root);

我正在考虑使用GetProperties() 检索PropertyInfo 对象的数组,然后使用GetValue() 获取这些属性的值,最后为每个值再次调用GetProperties() 并重复此过程直到整个对象图表已被访问,但我不确定这是否是最好的方法。

有什么建议吗?

编辑:

对于可达,我可以想到两个定义:

  1. 根对象的所有者可以访问的所有对象(公共可用对象)。
  2. 根对象所属的对象图引用的所有公共和私有对象。

第一个定义足以满足我的目的。

【问题讨论】:

  • 你需要一个递归算法。基本上它就像一个BF搜索。
  • 要获得更多/更好的建议,您必须说明它的用途,以及“可达”的确切含义。

标签: c# reflection reference


【解决方案1】:

您肯定需要字段,而不是属性。对象通过字段使其他对象保持活动状态,从不通过属性。您不需要特殊情况列表,因为它们包含一个内部数组,您可以使用 GetFields 找到该数组。但是,您需要特殊情况的数组。

顺便说一句,我已经实现了这个算法,发现它有效且有用。

【讨论】:

  • 既然你自己实现了这个算法,你能告诉我数组是否是我能找到的唯一特例吗? :)
  • 是的。您只需要考虑可以存储对其他对象的引用的“事物”。只有字段和数组可以做到这一点。
  • 他们可以装任何东西,没关系。它们只会使用字段引用其他对象。它们的实现细节无关紧要。如果您需要示例,请考虑一下链表或哈希表的内部外观。只是字段。
【解决方案2】:

以防万一有人觉得它有用,我将分享我从 usrHenk's 的答案中编写的递归方法,解决了我的问题:

static void EnumerateObjectsInRange(object root, HashSet<object> hashset)
{
    if (root == null || hashset.Contains(root))
    {
        return;
    }

    hashset.Add(root);
    FieldInfo[] fields = root.GetType().GetFields(BindingFlags.Static
                                                | BindingFlags.Instance
                                                | BindingFlags.Public
                                                | BindingFlags.NonPublic);

    foreach (FieldInfo field in fields)
    {
        object obj = field.GetValue(root);

        if (obj == null)
        {
            continue;
        }

        if (obj.GetType().IsSubclassOf(typeof(Array)))
        {
            foreach (object member in (Array)obj)
            {
                EnumerateObjectsInRange(member, hashset);
            }
        }

        EnumerateObjectsInRange(obj, hashset);
    }
}

这个方法仍然需要一些重构(并且它不检查 HashSet 是否为空),但它完成了工作。

要调用它,请提供根对象和一个空的 HashSet,其中将存储访问的对象。

【讨论】:

  • 不错的尝试,但仍远非理想。有很多事情需要特殊处理。例如值类型字段、覆盖 Equals() 和 GetHashCode() 方法的类、从另一个 AppDomain 代理的对象等。
  • 感谢您的提示。当 Equals() 和 GetHashCode() 使用ObjectIDGenerator 为不同的对象返回相同的值时,我制定了一个解决方案来处理这种情况,而我只是忽略了值类型字段,因为您无法获得对它们的引用,仅副本(但我仍在查看它们以了解它们是否包含引用类型字段)。关于 AppDomain,这超出了我的范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多