1

给定任意对象图中的两个 .NET 对象(根和叶)(由属性和集合链接),是否存在现有 API 或示例来构造路径(类似于 WPF 属性绑定路径或 XML XPath)从一个到另一个?“源”(即想要找出路径的对象)将是叶对象。

还必须支持索引位置。(例如。Foo.Bar[42].Baz["frog"].Quux)。

这主要用于错误报告——我想让对象记录一个错误,显示它们在对象模型中的位置,而不仅仅是它们的类型名称。(这很重要,因为同一类型的对象可能包含在大量其他对象类型中,并且修复任何问题所需的用户操作将根据该位置而有所不同。)

我可以通过为每个对象提供对其父对象的引用并递归地询问每个父对象如何到达子对象来手动滚动一些可以达到目的的东西。但在我这样做之前,我想知道是否有任何现有/更好的解决方案。(如果有人忘记更新父链接,或者一个对象可以通过两条不同的路径到达,这很脆弱,尽管这种情况应该很少见。)

4

2 回答 2

0

我没有在框架中看到任何接近的东西。

如果没有“父”属性,我认为您正在寻找“图中的最短路径”(http://en.wikipedia.org/wiki/Pathfinding),但由于复杂性和保持路径结构的内存要求。

于 2011-11-17T06:24:12.207 回答
0

这是您如何开始的一些非常简化的变体,希望这会有所帮助......

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace ConsoleApplication2
{
    class Test2
    {
        public bool BoolProp { get; set; }

        public int[] ArrayProp { get; set; }
    }

    class Test1
    {
        public string StringProp { get; set; }

        public Dictionary<string, Test2> DictionaryProp { get; set; }
    }

    class Program
    {


        private static string ObjToPathKey(object key)
        {
            if (key == null) return "null";
            if (key is string) return string.Format("\"{0}\"", key);
            return key.ToString();
        }

        public static IEnumerable<KeyValuePair<string, object>> GetFullTree(object root, string currentPath)
        {
            if (root == null) yield break;

            yield return new KeyValuePair<string, object>(currentPath, root);

            var type = root.GetType();
            if (!type.IsClass || type == typeof(string)) yield break;

            if (root is IEnumerable)
            {
                if (root is IDictionary)
                {
                    IDictionary d = (IDictionary) root;
                    foreach (var key in d.Keys)
                    {
                        var child = d[key];
                        foreach (var subchildPair in GetFullTree(child, string.Format("{0}[{1}]", currentPath, ObjToPathKey(key))))
                        {
                            yield return subchildPair;
                        }
                    }
                    yield break;
                }

                int i = 0;
                if (root is IList)
                {
                    foreach (var child in (IEnumerable)root)
                    {
                        foreach (var subChildPair in GetFullTree(child, string.Format("{0}[{1}]", currentPath, i)))
                        {
                            yield return subChildPair;
                        }
                        ++i;
                    }
                    yield break;
                }

                throw new NotSupportedException();
            }

            if (type.IsClass)
            {
                foreach (PropertyInfo propertyInfo in type.GetProperties())
                {
                    //TODO: Add indexers support
                    object propertyValue = propertyInfo.GetValue(root, null);
                    foreach (var subChildPair in GetFullTree(propertyValue, string.Format("{0}.{1}", currentPath, propertyInfo.Name)))
                    {
                        yield return subChildPair;
                    }
                }
            }
        }

        static void Main(string[] args)
        {
            Test1 t = new Test1()
                          {
                              StringProp = "Some value",
                              DictionaryProp = new Dictionary<string, Test2>()
                                                   {
                                                       {
                                                           "key1", new Test2()
                                                                       {
                                                                           ArrayProp = new[] {1, 2, 3},
                                                                           BoolProp = true
                                                                       }
                                                           },
                                                       {
                                                           "key 2", new Test2()
                                                                        {
                                                                            ArrayProp = new[] {4, 5, 6, 7},
                                                                            BoolProp = false
                                                                        }
                                                           }
                                                   }
                          };

            foreach (var pair in GetFullTree(t, "t"))
            {
                Console.WriteLine("{0} = {1}", pair.Key, pair.Value);
            }

            Console.Read();

            /* Program output:
                t = ConsoleApplication2.Test1
                t.StringProp = Some value
                t.DictionaryProp = System.Collections.Generic.Dictionary`2[System.String,Console
                Application2.Test2]
                t.DictionaryProp["key1"] = ConsoleApplication2.Test2
                t.DictionaryProp["key1"].BoolProp = True
                t.DictionaryProp["key1"].ArrayProp = System.Int32[]
                t.DictionaryProp["key1"].ArrayProp[0] = 1
                t.DictionaryProp["key1"].ArrayProp[1] = 2
                t.DictionaryProp["key1"].ArrayProp[2] = 3
                t.DictionaryProp["key 2"] = ConsoleApplication2.Test2
                t.DictionaryProp["key 2"].BoolProp = False
                t.DictionaryProp["key 2"].ArrayProp = System.Int32[]
                t.DictionaryProp["key 2"].ArrayProp[0] = 4
                t.DictionaryProp["key 2"].ArrayProp[1] = 5
                t.DictionaryProp["key 2"].ArrayProp[2] = 6
                t.DictionaryProp["key 2"].ArrayProp[3] = 7
             */
        }
    }
}
于 2011-11-17T06:50:48.967 回答