2010-01-19 14 views
1

J'ai le code suivant où, pour une raison quelconque, j'obtiens une exception KeyNotFoundException même si j'utilise une clé que j'ai récupérée quelques lignes plus haut. Est-ce que quelqu'un sait d'une situation où cela ne fonctionnerait pas? Je suis perplexe. BTW 'SchemaElementType est une énumération.Obtention de KeyNotFoundException lors de l'utilisation d'une clé précédemment récupérée à partir de la collection de clés?

public class DefaultValue 
{ 
private Dictionary<Parameter, string> _params; 

public DefaultValue(Dictionary<Parameter, string> parameters) 
{ 
     _params = parameters; 
} 

    public string GetParameterValue(string name) 
    { 
     foreach(Parameter param in _params.Keys) 
     { 
      if(param.ParamName.Equals(name)) 
      { 
       // **** Issue here **** 
       return _params[param]; 
      } 
     } 
     return string.Empty; 
    } 
} 

[DataContract] 
public class Parameter 
    { 
     #region Members 
     private Guid _guid; 
     private Guid _formulaGuid; 
     private string _name; 

     #endregion 

     #region Constructor 
     public Parameter(Guid guid, Guid formulaGuid, string name, SchemaElementType type) 
     { 
      ParamGuid = guid; 
      FormulaGuid = formulaGuid; 
      ParamName = name; 
      ParamType = type; 
     } 

     public Parameter() 
     {} 

     #endregion 

     #region Properties 

     [DataMember] 
     public Guid ParamGuid 
     { 
      get { return _guid; } 
      set { _guid = value; } 
     } 

     [DataMember] 
     public Guid FormulaGuid 
     { 
      get { return _formulaGuid; } 
      set { _formulaGuid = value; } 
     } 

     [DataMember] 
     public string ParamName 
     { 
      get { return _name; } 
      set { _name = value; } 
     } 

     [DataMember] 
     public SchemaElementType ParamType { get; set; } 

     #endregion 

     #region Overrides 

     public bool Equals(Parameter other) 
     { 
      if (ReferenceEquals(null, other)) return false; 
      if (ReferenceEquals(this, other)) return true; 
      bool result =other._guid.Equals(_guid); 
      result = result && other._formulaGuid.Equals(_formulaGuid); 
      result = result && Equals(other._name, _name); 
      result = result && Equals(other.ParamType, ParamType); 

      return result; 
     } 

     public override int GetHashCode() 
     { 
      unchecked 
      { 
       int result = _guid.GetHashCode(); 
       result = (result*397)^_formulaGuid.GetHashCode(); 
       result = (result*397)^(_name != null ? _name.GetHashCode() : 0); 
       result = (result*397)^ParamType.GetHashCode(); 
       return result; 
      } 
     } 

     public override bool Equals(object obj) 
     { 
      if (ReferenceEquals(null, obj)) return false; 
      if (ReferenceEquals(this, obj)) return true; 
      if (obj.GetType() != typeof (Parameter)) return false; 
      return Equals((Parameter) obj); 
     } 

     #endregion 
    } 
+0

Avez-vous du code qui indique le problème? –

Répondre

0

Vous pouvez profiter de la KeyValuePair <> classe:

foreach(var item in _params) 
{ 
    if(item.Key.ParamName.Equals(name)) 
    { 
     return item.Value; 
    } 
} 
+0

hmm, var abus :) Je voudrais rester à l'aide du KeyValuePair comme var ne doit être utilisé lorsque vous ne connaissez pas le type (selon le C# référence), mais je suppose que c'est un autre débat qui se passe ailleurs sur SO :) – Wayne

+2

@Wayne - c'est évidemment un point subjectif, mais quelle information supplémentaire cela vous dirait-il? Pourquoi encombrer le code? IMO l'utilisation 'var' est parfaitement clair et acceptable ici. –

+0

J'ai marqué cela comme la réponse car elle m'a aidé à corriger le bug (calendrier serré) bien que j'ai donné des votes à Mark et Rune FS car ils ont tous deux souligné le besoin d'améliorer le codage de la classe Parameter/utilisation de celle-ci comme clé. Je vais essayer de présenter ces changements dès que possible. Merci les gars. –

1

bien à proprement parler, vous n'êtes pas récupérer la (clé de recherche) quelques lignes ci-dessus vous sont retreiving un objet à un moment donné a été utilisé pour le calcul de la clé de hachage.

Lorsque vous insérez dans un dictionnaire, la méthode GetHashKey de l'objet clé est appelée. Si cela change à partir du moment où vous insérez la paire clé-valeur au moment où votre code est exécuté, vous obtiendrez le comportement décrit. (sauf si le GetHashKey no renvoie une valeur correspondant à une clé d'une paire clé-valeur différente, dans ce cas vous obtenez un comportement vraiment bizarre et pas une exception)

Je chercherais la valeur de la clé de hachage quand l'insertion et quand retreiving et voir s'il y a un décalage entre les

+0

change du type vous .. ne devrait-il pas être le temps? Je crois que c'est ce que vous vouliez dire? – Wayne

+0

@Wayne vous corrigé et j'ai fait le changement tu –

2

Je me inquiète du fait que Parameter est mutable. Si (après l'ajoutant au dictionnaire) vous avez modifié l'une des valeurs utilisées lors de la génération GetHashCode() (c'est-à-dire tous), puis tous les paris sont désactivés et pas garanti de voir votre article à nouveau. Je ne voudrais pas faire ces setters publics, à savoir

[DataMember] 
    public string ParamName // applies to all the properties, not just this one 
    { 
     get { return _name; } 
     private set { _name = value; } 
    } 

Actaully, je serais probablement laisser tomber les champs explicites et utiliser C# 3.0 propriétés mises en œuvre automatiquement:

[DataMember] 
    public string ParamName { get; private set; } 

À titre d'exemple qui casse en changeant le paramètre :

var data = new Dictionary<Parameter, string>(); 
    Parameter p; 
    data.Add((p = new Parameter(Guid.NewGuid(), Guid.NewGuid(), "abc", 
     SchemaElementType.A)), "def"); 
    var dv = new DefaultValue(data); 
    string val1 = dv.GetParameterValue("abc"); // returns "def" 
    p.ParamGuid = Guid.NewGuid(); 
    string val2 = dv.GetParameterValue("abc"); // BOOM 

Comme pensée finale; Si l'utilisation typique est de rechercher par string, alors pourquoi ne pas utiliser le nom comme clé pour le dictionnaire interne? Pour le moment, vous n'utilisez pas correctement le dictionnaire.

+0

Je suis à peu près sûr que la touche Parameter n'est pas du tout modifiée entre add et get mais je vais vérifier. Je viens juste de prendre le code de quelqu'un d'autre donc je ne suis pas encore totalement au courant de son utilisation. Totalement d'accord avec vos pensées sur la mise en œuvre, juste besoin d'accéder à l'impact de faire des changements. –