Получение KeyNotFoundException при использовании ключа, ранее извлеченного из коллекции ключей?
У меня есть следующий код, где по какой-то причине я получаю KeyNotFoundException, хотя я использую ключ, который я получил несколько строк выше. Кто-нибудь знает ситуацию, когда это не сработает? Я в тупике. Кстати, SchemaElementType - это перечисление.
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
}
3 ответа
Вы можете воспользоваться классом KeyValuePair<>:
foreach(var item in _params)
{
if(item.Key.ParamName.Equals(name))
{
return item.Value;
}
}
Я беспокоюсь о том, что Parameter
изменчиво Если (после добавления его в словарь) вы изменили любое из значений, которые используются при генерации GetHashCode()
(т.е. все они), тогда все ставки сняты, и вы не гарантированно увидите свой товар снова. Я бы не стал делать эти публичные сеттеры, т.е.
[DataMember]
public string ParamName // applies to all the properties, not just this one
{
get { return _name; }
private set { _name = value; }
}
На самом деле, я бы, вероятно, отбросил явные поля и использовал бы автоматически реализованные свойства 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
, то почему бы не использовать имя в качестве ключа для внутреннего словаря? В данный момент вы не используете словарь должным образом.
Строго говоря, вы не получаете (ключ поиска) несколько строк выше, вы получаете объект, который в какой-то момент использовался для вычисления ключа хеша.
При вставке в словарь будет вызываться метод GetHashKey ключевого объекта. Если это меняется со времени, когда вы вставляете пару ключ-значение, до времени выполнения вашего кода, вы получите описанное поведение. (кроме случаев, когда GetHashKey no возвращает значение, соответствующее ключу другой паре ключ-значение, в этом случае вы получаете действительно странное поведение, а не исключение)
Я бы посмотрел значение ключа хеша при вставке и при получении и посмотрел, есть ли между ними несоответствие