2010-01-19 4 views
1

У меня есть следующий код, по какой-то причине я получаю исключение KeyNotFoundException, хотя я использую ключ, который я извлек из пары строк выше. Кто-нибудь знает о ситуации, когда это не сработает? Я в тупике. BTW 'SchemaElementType - это перечисление.Получение KeyNotFoundException при использовании ключа, ранее полученного из коллекции ключей?

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

У вас есть код, который фактически показывает проблему? –

ответ

0

Вы можете воспользоваться> класса KeyValuePair <:

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

hmm, var abuse :) Я бы придерживался использования KeyValuePair , так как var должен использоваться только тогда, когда вы не знаете тип (согласно C#), но я думаю, что это еще одна дискуссия, которая происходит в другом месте на SO :) – Wayne

+2

@Wayne - это, очевидно, субъективный момент, но какая дополнительная информация вам расскажет? Зачем загромождать код? ИМО использование 'var' совершенно ясное и приемлемое здесь. –

+0

Я отметил это как ответ, поскольку он помог мне получить исправленную ошибку (жесткий график), хотя я дал голоса как Mark, так и Rune FS, поскольку оба они подчеркнули необходимость улучшения кодирования класса Parameter/использования его как ключ. Я собираюсь объединить эти изменения как можно скорее. Спасибо, парни. –

1

Ну, строго говоря, вы не извлекая (ключ поиска) несколько строк выше вас retreiving объект, который в какой-то момент была использована для вычисления хэш-ключа.

Когда вы вставляете в словарь, вызывается метод GetHashKey для ключевого объекта. Если это изменится с момента ввода пары ключ-значение во время выполнения кода, вы получите описанное поведение. (если не причина, если GetHashKey no возвращает значение, соответствующее ключу другой паре ключ-значение, в этом случае вы получите действительно странное поведение, а не исключение)

Я бы искал значение хэш-ключа, когда вставки и когда retreiving и посмотреть, если есть несоответствие между ними

+0

меняется от типа вас .. не должно ли это быть? я верю, что это вы имели в виду? – Wayne

+0

@Wayne вы исправили, и я внес изменения tu –

2

Я беспокоюсь о том, что Parameter является изменяемым. Если (после, добавив его в словарь), вы изменили любые значения, которые используются при создании GetHashCode() (т. Е. Все из них), тогда все ставки отключены, а вы - , а не, чтобы снова увидеть ваш товар. Я бы не сделать эти публичные сеттеры, т.е.

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

Actaully, я бы, вероятно, падение явные поля и использовать C# 3.0 автоматически реализованы свойства:

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

В качестве примера, который расщепляет путем изменения параметра :

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 

В качестве окончательной мысли; если типичное использование - поиск по string, то почему бы не использовать это имя в качестве ключа для внутреннего словаря? На данный момент вы не используете словарь правильно.

+0

Я почти уверен, что ключ параметра не изменяется вообще между add и get, но я проверю. Я только что получил код от кого-то еще, но не полностью осознал его использование. Полностью согласен с вашими мыслями о реализации, просто нужно получить доступ к последствиям внесения изменений. –