Pregunta

Tengo el siguiente código donde por alguna razón, me estoy poniendo un KeyNotFoundException a pesar de que estoy usando una llave que me había retrived un par de líneas más arriba. ¿Alguien sabe de una situación en la que esto no funcionaría? Estoy perplejo. BTW 'SchemaElementType es una enumeración.

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
    }
¿Fue útil?

Solución

Puede tomar ventaja de la clase KeyValuePair <>:

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

Otros consejos

Me preocupa el hecho de que Parameter es mutable. Si ( después añadir al diccionario) ha cambiado cualquiera de los valores que se utilizan cuando se genera GetHashCode() (es decir, todos ellos), todas las apuestas están apagadas y que son no garantizada para ver su artículo de nuevo. Yo no haría estos emisores públicos, es decir.

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

Actaully, probablemente me deje caer los campos explícitos y uso de C # 3.0 propiedades implementadas automáticamente:

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

Como un ejemplo que rompe cambiando el parámetro:

    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

Como reflexión final; si el uso típico es para buscar por string, entonces ¿por qué no usar el nombre como la clave para el diccionario interno? Por el momento no está utilizando el diccionario correctamente.

Bueno, estrictamente hablando no está trayendo el (clave de búsqueda) unas líneas anteriores que se retreiving un objeto que en algún momento fue utilizado para el cálculo de la clave hash.

Cuando se inserta en un diccionario el método GetHashKey del objeto clave serán llamados. Si eso cambia desde el momento de insertar el par clave-valor al tiempo de su código se ejecuta obtendrá el comportamiento descrito. (A menos de causa si el GetHashKey no devuelve un valor que coincide con una clave de un par clave-valor diferente, en ese caso se obtiene no es un comportamiento muy raro una excepción)

Me gustaría buscar el valor de la clave hash al insertar y cuando al recuperar y ver si hay un desajuste entre ellos

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top