2012-08-15 58 views
3

在方法上執行單元測試時收到上述錯誤消息。我知道問題出在哪裏,我只是不知道它爲什麼不出現在字典中。System.Collections.Generic.KeyNotFoundException:給定密鑰在字典中不存在

這裏是字典:

var nmDict = xelem.Descendants(plantNS + "Month").ToDictionary(
    k => new Tuple<int, int, string>(int.Parse(k.Ancestors(plantNS + "Year").First().Attribute("Year").Value), Int32.Parse(k.Attribute("Month1").Value), k.Ancestors(plantNS + "Report").First().Attribute("Location").Value.ToString()), 
    v => { 
      var detail = v.Descendants(plantNS + "Details").First(); 
      return new HoursContainer 
      { 
       BaseHours = detail.Attribute("BaseHours").Value, 
       OvertimeHours = detail.Attribute("OvertimeHours").Value, 
       TotalHours = float.Parse(detail.Attribute("BaseHours").Value) + float.Parse(detail.Attribute("OvertimeHours").Value) 
      }; 
     }); 

var mergedDict = new Dictionary<Tuple<int, int, string>, HoursContainer>(); 

foreach (var item in nmDict) 
{ 
    mergedDict.Add(Tuple.Create(item.Key.Item1, item.Key.Item2, "NM"), item.Value); 
} 


var thDict = xelem.Descendants(plantNS + "Month").ToDictionary(
    k => new Tuple<int, int, string>(int.Parse(k.Ancestors(plantNS + "Year").First().Attribute("Year").Value), Int32.Parse(k.Attribute("Month1").Value), k.Ancestors(plantNS + "Report").First().Attribute("Location").Value.ToString()), 
    v => { 
      var detail = v.Descendants(plantNS + "Details").First(); 
      return new HoursContainer 
      { 
       BaseHours = detail.Attribute("BaseHours").Value, 
       OvertimeHours = detail.Attribute("OvertimeHours").Value, 
       TotalHours = float.Parse(detail.Attribute("BaseHours").Value) + float.Parse(detail.Attribute("OvertimeHours").Value) 
      }; 
     }); 

foreach (var item in thDict) 
{ 
    mergedDict.Add(Tuple.Create(item.Key.Item1, item.Key.Item2, "TH"), item.Value); 
} 
     return mergedDict;         

}

和這裏是被測試的方法,包括:

protected IList<DataResults> QueryData(HarvestTargetTimeRangeUTC ranges, 
     IDictionary<Tuple<int, int, string>, HoursContainer> mergedDict) 
{    
    var startDate = new DateTime(ranges.StartTimeUTC.Year, ranges.StartTimeUTC.Month, 1); 
    var endDate = new DateTime(ranges.EndTimeUTC.Year, ranges.EndTimeUTC.Month, 1); 
    const string IndicatorName = "{6B5B57F6-A9FC-48AB-BA4C-9AB5A16F3745}"; 

    DataResults endItem = new DataResults(); 
    List<DataResults> ListOfResults = new List<DataResults>();        

    var allData = 

    (from vi in context.vDimIncidents 
    where vi.IncidentDate >= startDate.AddYears(-3) && vi.IncidentDate <= endDate 
     select new 
     { 
      vi.IncidentDate, 
      LocationName = vi.LocationCode, 
      GroupingName = vi.Location, 
      vi.ThisIncidentIs, vi.Location 
     }); 

    var finalResults = 

      (from a in allData 
      group a by new { a.IncidentDate.Year, a.IncidentDate.Month, a.LocationName, a.GroupingName, a.ThisIncidentIs, a.Location } 
       into groupItem 
      select new 
      { 
       Year = String.Format("{0}", groupItem.Key.Year), 
       Month = String.Format("{0:00}", groupItem.Key.Month), 
       groupItem.Key.LocationName, 
       GroupingName = groupItem.Key.GroupingName, 
       Numerator = groupItem.Count(), 
       Denominator = mergedDict[Tuple.Create(groupItem.Key.Year, groupItem.Key.Month, groupItem.Key.LocationName)].TotalHours, 
       IndicatorName = IndicatorName,       
      }).ToList(); 


    for (int counter = 0; counter < finalResults.Count; counter++) 
    { 
     var item = finalResults[counter]; 
     endItem = new DataResults(); 
     ListOfResults.Add(endItem); 
     endItem.IndicatorName = item.IndicatorName; 
     endItem.LocationName = item.LocationName; 
     endItem.Year = item.Year; 
     endItem.Month = item.Month; 
     endItem.GroupingName = item.GroupingName; 
     endItem.Numerator = item.Numerator; 
     endItem.Denominator = item.Denominator;    
    } 

    foreach(var item in mergedDict) 
    { 
     if(!ListOfResults.Exists(l=> l.Year == item.Key.Item1.ToString() && l.Month == item.Key.Item2.ToString() 
       && l.LocationName == item.Key.Item3)) 
     { 
      for (int counter = 0; counter < finalResults.Count; counter++) 
      { 
       var data = finalResults[counter]; 
       endItem = new DataResults(); 
       ListOfResults.Add(endItem); 
       endItem.IndicatorName = data.IndicatorName; 
       endItem.LocationName = item.Key.Item3; 
       endItem.Year = item.Key.Item1.ToString(); 
       endItem.Month = item.Key.Item2.ToString(); 
       endItem.GroupingName = data.GroupingName; 
       endItem.Numerator = 0; 
       endItem.Denominator = item.Value.TotalHours; 
      } 
     } 
    } 
    return ListOfResults; 
} 

這裏發生該錯誤:

Denominator = mergedDict[Tuple.Create(groupItem.Key.Year, groupItem.Key.Month, groupItem.Key.LocationName)].TotalHours, 

我不清楚爲什麼它不存在於關鍵中。關鍵在於一個int,int,字符串(年,月,位置),這就是我所分配的。

我看過所有關於此錯誤信息的其他線索,但我沒有看到任何適用於我的情況的東西。

我不確定使用哪些標籤,但從我的理解詞典是用linq創建的xml,查詢是linq to sql,它是C#的所有部分,因此我使用了所有標籤。如果這是不正確的,那麼我提前道歉。

+3

請發佈一個小*重現*的例子,讓我們看看。 – asawyer 2012-08-15 15:31:47

+0

@asawyer請解釋您可重複生成的示例的含義 – 2012-08-15 15:33:24

+2

字符串的「平等」形式是否與字典的IEqualityComparer匹配?例如。在給定的語言環境中,您的鍵盤匹配是否區分大小寫,但字典在另一個語言環境中是否區分大小寫,等等? – 2012-08-15 15:40:24

回答

6

問題在於您要存儲在Dictionary中的密鑰與您正試圖查找的密鑰之間的比較。

當您向Dictionary添加內容或訪問Dictionary的索引器時,它使用GetHashCode()方法獲取密鑰的哈希值。 Tuple的哈希碼對於Tuple的該實例是唯一的。這意味着除非您將Tuple類的完全相同的實例傳入索引器,否則它將不會找到以前存儲的值。您使用mergedDict[Tuple.Create(...會創建一個全新的元組,其哈希碼與存儲在Dictionary中的哈希碼不同。

我會建議創建自己的類作爲密鑰,並在該類上實現GetHashCode()和Equality方法。這樣Dictionary就能夠找到你以前存儲的內容。

更多: 其原因,這是令人困惑了很多人的是,這樣的事情StringInt32String.GetHashCode()將返回相同的哈希代碼具有相同值的兩個不同的實例。更專業化的課程如Tuple並不總是相同。 Tuple的實現者可能已將每個輸入的哈希碼獲得到Tuple並將它們添加到一起(或某物),但通過反編譯器運行Tuple可以看到情況並非如此。

+0

非常感謝您的幫助。 – 2012-08-15 15:58:27

+1

如果您使用ReSharper,您可以按Alt + Ins,讓它爲您生成所有的GetHashCode(),Equals()等方法。他們仍然需要一些手動工作,但它可以節省很多時間。 – 2012-08-15 16:02:04

相關問題