Système.Les Collections.Génériques.KeyNotFoundException: La clé donnée n'était pas présent dans le dictionnaire
Je reçois le message d'erreur ci-dessus lors de l'exécution d'un test unitaire sur une méthode. Je sais où est le problème, je ne sais pas pourquoi il n'est pas présent dans le dictionnaire.
Ici est le dictionnaire:
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;
}
et voici la méthode qui est en cours de test:
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;
}
L'erreur se produit ici:
Denominator = mergedDict[Tuple.Create(groupItem.Key.Year, groupItem.Key.Month, groupItem.Key.LocationName)].TotalHours,
Je ne comprends pas pourquoi il n'est pas présent dans la clé. La clé se compose sur un int, int, string (année, mois, emplacement) et c'est ce que j'ai attribuée.
J'ai regardé tous les autres threads concernant ce message d'erreur mais je ne vois rien qui s'appliquait à ma situation.
Je n'étais pas sûr de ce que les balises à mettre sur ce sujet, mais à partir de ma compréhension du dictionnaire a été créé avec linq to xml, la requête linq to sql et c'est toute la partie de C# j'ai donc utilisé toutes les balises. si cette information était inexacte alors je m'excuse à l'avance.
Veuillez expliquer ce que vous entendez par exemple reproductible
Le formulaire de "l'égalité" pour la chaîne correspondre à celle du dictionnaire de l'IEqualityComparer? E. g. est-ce que votre clé-match de la casse dans un endroit donné, mais le dictionnaire est à la recherche de la casse dans une autre région, et ainsi de suite?
Petite = environ 7 lignes (au moins 2 blocs énormes avec des barres de défilement), reproductible = on peut obtenir les mêmes résultats que vous êtes en exécutant votre échantillon (tous les 7 lignes) ou de l'insertion de votre échantillon dans une certaine base, programme C#/LINQPad
Levenkov Si je savais comment faire pour obtenir les mêmes résultats que je suis à la recherche d'en sept lignes, alors je l'ai créé en sept lignes en premier lieu. Mon dictionnaire à elle seule plus de sept lignes.
OriginalL'auteur Programming Newbie | 2012-08-15
Vous devez vous connecter pour publier un commentaire.
Le problème, c'est grâce à des comparaisons entre les touches que vous stockez dans la
Dictionary
et les touches que vous essayez de chercher.Lorsque vous ajoutez quelque chose à un
Dictionary
ou d'accéder à l'indexation d'unDictionary
il utilise leGetHashCode()
méthode pour obtenir une valeur de hachage de la clé. Le hashcode pour unTuple
est unique à cette instance de laTuple
. Cela signifie que si vous êtes de passage dans la même instance de laTuple
classe dans l'indexeur, il ne trouve pas auparavant à valeur stockée. Votre utilisation demergedDict[Tuple.Create(...
crée un tout nouveau Tuple avec un hachage différent que le code est stocké dans leDictionary
.Je voudrais vous recommandons de créer votre propre classe à utiliser comme clé et la mise en œuvre de
GetHashCode()
et de l'Égalité entre les méthodes de cette classe. De cette façon, le Dictionnaire sera en mesure de trouver ce que vous avez précédemment y sont stockées.Plus:
La raison de ce qui est source de confusion pour beaucoup de gens, c'est que quelque chose comme
String
ouInt32
,String.GetHashCode()
sera de retour le même code de hachage pour les deux instances différentes qui ont la même valeur. Un de plus spécialisé de classe commeTuple
ne sont pas toujours les mêmes. Le réalisateur deTuple
pouvais avoir obtenu le code de hachage de chaque entrée à laTuple
et ajoutés à l'ensemble (ou quelque chose), mais l'exécution n-uplet par le biais d'un decompiler vous pouvez voir que ce n'est pas le cas.Si vous utilisez ReSharper, vous pouvez appuyer sur Alt+Ins et faire générer tous les GetHashCode(), Equals(), etc méthodes pour vous. Ils ont encore besoin d'un peu de travail manuel, mais il permet d'économiser beaucoup de temps.
OriginalL'auteur Kevin Kalitowski