构造两个对象之间的导航路径



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

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

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

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

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

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
             */
        }
    }
}

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

没有"父"属性,我认为你在寻找"最短路径在一个图"(http://en.wikipedia.org/wiki/Pathfinding),但它看起来不像一个很好的选择跟踪/错误日志由于复杂性和内存需求,以保持路径结构。

最新更新