Question

Is there an easy way to dig in to an object and find a property or field by its hashcode? This could be a nested property or a value in a collection. The reason I ask is that I occasionally get WPF warnings that look like:

System.Windows.ResourceDictionary Warning: 9 : Resource not found;
  ResourceKey='#FF000000'; ResourceKey.HashCode='51639504';
  ResourceKey.Type='System.Windows.Media.SolidColorBrush' 

The warning doesn't always appear and I'm having the hardest time tracking it down. I figure if I knew which object had that hashcode, I could get closer to fixing this. For instance, if I had this object:

var first = new { a = 1, b = 2, d = new { aa = 11, bb = 22 } };

and called this on it:

string str = FindHashCode(first, 22);

the result would be:

"Anon > d > bb.hashcode = 22"

or something similar. (I'm ignoring hashcode collisions for now)


Edit: Here's what I'll use based on @Alberto's answer. It searches both fields and properties whether public or non-public. It includes support for IEnumerables (Lists, Arrays, etc.) and more specifically IDictionaries. It also handles hashcode collisions. If two objects have the same hashcode, the StringBuilder will have a separate line for each object.

using System.Reflection;

static string FindHashCode(object o, int hashCode)
{
    StringBuilder strb = new StringBuilder();
    FindHashCode(o, hashCode, o.GetType().Name, strb);
    return strb.ToString().Trim();
}

static void FindHashCode(object o, int hashCode, string path, StringBuilder strb)
{
    if (o.GetHashCode() == hashCode)
    {
        strb.AppendLine(path + ".hashcode = " + hashCode);
    }

    foreach (var field in GetFieldInfo(o))
    {
        if (field.Item1 == null || object.ReferenceEquals(o, field.Item1))
            continue;

        Type type = field.Item1.GetType();
        if (type.IsPrimitive)
        {
            if(field.Item1.GetHashCode() == hashCode)
                strb.AppendLine(path + " > " + field.Item2 + ".hashcode = " + hashCode);
        }
        else
        {
            FindHashCode(field.Item1, hashCode, path + " > " + field.Item2, strb);
        }
    }
}

static IEnumerable<Tuple<object, string>> GetFieldInfo(object arg)
{
    var ienum = arg as System.Collections.IEnumerable;
    var idict = arg as System.Collections.IDictionary;

    if (ienum == null && idict == null)
    {
        BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
        Type type = arg.GetType();

        var list = type.GetFields(bf).Select(s => new Tuple<object, string>(s.GetValue(arg), s.Name)).Concat(
            type.GetProperties(bf).Select(s => new Tuple<object, string>(s.GetValue(arg, null), s.Name)));

        foreach (var item in list)
        {
            yield return item;
        }
    }
    else if (idict != null)
    {
        foreach (System.Collections.DictionaryEntry item in idict)
        {
            yield return new Tuple<object, string>(item.Key, string.Format("Dict[{0}].Key", item.Key));
            yield return new Tuple<object, string>(item.Value, string.Format("Dict[{0}].Value", item.Key));
        }
    }

    //note that dictionaries implement IEnumerable
    else if (ienum != null && !(ienum is string)) 
    {
        int count = 0;
        foreach (var item in ienum)
        {
            yield return new Tuple<object, string>(item, string.Format("this[{0}]", count));
            count++;
        }
    }
}
Was it helpful?

Solution

Here an implementation that search recursively in an object graph for a property with a specific hashcode:

static string FindHashCode(object o, int hashCode)
{
    return FindHashCodeImpl(o,hashCode, o.GetType().Name);
}

static string FindHashCodeImpl(object o, int hashCode, string partialPath)
{
    var type = o.GetType();
    var properties = type.GetProperties();
    foreach (var property in properties)
    {
        var propValue = property.GetValue(o);
        if (propValue.GetHashCode() == hashCode)
        {
            return partialPath + " > " + property.Name + ".hashcode = " + hashCode;
        }

        var path = FindHashCodeImpl(propValue, hashCode, partialPath + " > " + property.Name);
        if (path != null)
        {
            return path;
        }
    }
    return null;
}

Use it like:

var o = new { a = 1, b = 2, d = new { aa = 11, bb = 22 } };

var s = FindHashCode(o, 22); //Output "<>f__AnonymousType1`3 > d > bb.hashcode = 22"

You should extend it to search inside fields as well.

P.S I didn't test it for every scenario, but it should work...

OTHER TIPS

There's no automatic way to search a graph of objects for a member whose hashcode matches a certain value. But if you know the structure (like a List) then you can go along and GetHashCode() for each one and return the matches (of which there could be many). I think you must have some concept of the data you're working with, some container such as a list or tree, right?

The Visual Studio debugger also lets you assign Object IDs to items in the watches so that you can know that two references are to the same item, in case that helps.

I think there are faster ways to find your bug.

Trace WPF System.Windows.ResourceDictionary warning Resource not found

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top