System.Collections.Generic.KeyNotFoundException:给定

2019-09-21 06:04发布

上的方法进行单元测试时收到的上述错误信息。 我知道问题所在,我只是不知道为什么它不存在于字典。

这里是词典:

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 to XML创建,查询LINQ to SQL和它的C#的所有部分,所以我用所有的标签。 如果这是不正确的话,我提前道歉。

Answer 1:

问题是你是存储在按键之间的比较Dictionary ,你正试图查找键。

当您添加的东西到Dictionary或访问的索引Dictionary它使用GetHashCode()方法来获得关键的哈希值。 一个哈希码Tuple是唯一的该实例的Tuple 。 这意味着,除非你是通过在完全相同的实例Tuple类为索引,也不会找到以前保存的值。 您的使用mergedDict[Tuple.Create(...创建一个具有不同的散列码不是存储在一个全新的元组Dictionary

我会建议创建自己的类为重点,以使用和实施GetHashCode() ,并在该类平等方法。 这样的解释就能找到你以前存储在那里。

更多:这是混淆了很多人的原因是,像StringInt32String.GetHashCode()将返回相同的哈希代码具有相同值的两个不同的实例。 更专业类,如Tuple并不总是工作一样。 的实施者Tuple本来可以每个输入的哈希码Tuple ,并添加在一起(或某事),而是通过反编译运行的元组你可以看到,这是情况并非如此。



文章来源: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary