Reflection: Search object for string value, recursively, and then reporting paths
I am trying to look for a value in a complex object. Does anyone know if there is a helper class out there that does this already?
Would like to be able to search an object, while observing endless loop protection to find a tostring value that contains "foo" and then to return the property path that foo was found in. Or an array of paths foo was found in.
So if someone has handy existing code before I undertake this myself; I w开发者_Go百科ould be most grateful.
The key is you want to keep a Stack
of the current property while you recursively search for the value you're after and also a HashSet
of visited objects and skip them. You also want to be careful with your exception handling so an exception in the middle doesn't mess up the stack.
public static string[] FindPathToProperty(object item, string propertyValueToFind)
{
var pathToProperty = new Stack<string>();
var visitedObjects = new HashSet<object> {item};
FindPathToProperty(item, propertyValueToFind, pathToProperty, visitedObjects);
var finalPath = pathToProperty.ToArray();
Array.Reverse(finalPath);
return finalPath;
}
private static bool FindPathToProperty(object item, string propertyValueToFind, Stack<string> pathToProperty, HashSet<object> visitedObjects)
{
foreach (var property in item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
try
{
var value = property.GetValue(item, null);
if (visitedObjects.Contains(value))
{
continue;
}
visitedObjects.Add(value);
pathToProperty.Push(property.Name);
bool found = false;
try
{
found = propertyValueToFind.Equals(value) ||
FindPathToProperty(value, propertyValueToFind, pathToProperty, visitedObjects);
}
finally
{
if (!found)
{
pathToProperty.Pop();
}
}
if (found)
{
return true;
}
}
catch
{
continue;
}
}
return false;
}
public static void Test()
{
Test(new { X = "find" }, "X");
Test(new { X = "no", Y = "find" }, "Y");
Test(new { A = new { X = "no", Y = "find" } }, "A.Y");
}
private static void Test(object item, string expected)
{
string actual = string.Join(".", FindPathToProperty(item, "find"));
Console.WriteLine("{0} : {1}\r\n {2}",
actual == expected ? "ok " : "BAD",
expected,
actual);
}
精彩评论