给定任意对象图中的两个.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),但它看起来不像一个很好的选择跟踪/错误日志由于复杂性和内存需求,以保持路径结构。