2014-03-06 21 views
4

有沒有一種簡單的方法來挖掘對象並通過其哈希碼找到屬性或字段?這可以是嵌套屬性或集合中的值。我想問的原因是,我偶爾會看起來像WPF警告:如何通過哈希碼查找對象?

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

警告並不總是出現,我有困難的時候跟蹤下來。我想,如果我知道哪個對象有散列碼,我可以更接近於解決這個問題。舉例來說,如果我有這個對象:

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

,並呼籲這個就可以了:

string str = FindHashCode(first, 22); 

的結果將是:

"Anon > d > bb.hashcode = 22" 

或類似的東西。 (我現在忽略散列碼衝突)


編輯:下面是我將基於@ Alberto的回答使用的內容。它搜索字段和屬性,無論是公開的還是非公開的。它包括對IEnumerables(列表,數組等)的支持,更具體地說是支持IDictionaries。它也處理散列碼衝突。如果兩個對象具有相同的散列碼,則StringBuilder將爲每個對象都有一個單獨的行。

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++; 
     } 
    } 
} 
+1

幾個對象可能具有相同的哈希碼,所以有不作爲「對應」的散列碼的對象這樣的事情。 –

+0

我現在忽略散列碼碰撞 – user2023861

回答

2

這裏說的對象圖遞歸搜索屬性與特定的散列碼的實現:

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; 
} 

這樣使用它:

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" 

你應該把它擴展到搜索內部字段以及。

P.S我沒有測試它的每一個場景,但它應該工作...

+0

不錯。但要留意循環引用。而且,忽略私有/受保護/繼承的成員。我認爲接口屬性不會包含(?)。 –

+1

如果將GetProperties的BindingFlags參數設置爲'BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance',你會得到非公衆成員。 – user2023861

+0

此外,一個快速的說明,property.GetValue(o)似乎需要。淨4.5。較早版本的.Net需要第二個參數。它可以爲null。 – user2023861

1

有沒有自動的方式來搜索哈希碼匹配某個值的成員的對象的圖形。但是如果你知道結構(就像一個List)那麼你可以沿着GetHashCode()並返回匹配(其中可能有很多)。我認爲你必須對你正在使用的數據有一些概念,比如列表或樹等容器,對吧?

Visual Studio調試器還允許您將對象ID分配給手錶中的項目,以便您可以知道兩個引用是相同的項目,以防有所幫助。

我認爲有更快的方式找到你的錯誤。

Trace WPF System.Windows.ResourceDictionary warning Resource not found