2013-07-18 3 views
0

Я программист-любитель, и это кажется простой проблемой для исправления, но я просто не могу понять, как это сделать. Ниже приведен код C#, который не действует, как я хочу. Я ожидаю, что для этого вернется 3, но вместо этого выбрасывает KeyNotFoundException. Списки одинаковы, так что не следует ли возвращать 3? Спасибо за любую помощь.C# Словарь, дающий KeyNotFoundException, не знаю почему

Dictionary<object, double> dict = new Dictionary<object, double>(); 
dict.Add(new List<object>() { "a", "b" }, 3); 
double output = dict[new List<object>() { "a", "b" }]; 
+0

Использование объекта List <> в качестве ключа из словаря не является хорошей идеей, она идет против большинства общих случаев использования. – EkoostikMartin

+0

Что было бы лучше заменить? Если у меня есть список объектов, но я не знаю, сколько объектов есть или какой тип они есть, как их сопоставить с числами? – vlts

+0

хорошо @ Daniel Hilgarth предоставил вам достойную альтернативу «Tuple», но чтобы дать более конкретный ответ, вам нужно будет привести примеры того типа объектов, который вам нужно поместить в словарь. – EkoostikMartin

ответ

8

List<T> является ссылочным типом без специального Equals реализации. Итак, в вашем случае, в то время как оба экземпляра списка имеют одинаковый контент, они все еще являются разными экземплярами и как таковые не считаются равными при поиске ключей.

В зависимости от ваших потребностей, вы можете использовать различные решения:

  1. Если вы всегда имеют одинаковое количество элементов в списке, вы можете использовать Кортеж:

    Dictionary<Tuple<string, string>, double> dict = 
        new Dictionary<Tuple<string, string>, double>(); 
    dict.Add(Tuple.Create("a", "b"), 3); 
    double output = dict[Tuple.Create("a", "b")]; 
    
  2. Если количество элементов отличается, вы можете создать свой собственный список, который сравнивает его содержимое.

+0

Спасибо. Это из-за того, что некоторые объекты (например, списки) хранятся по ссылке, а другие нет? – vlts

+0

@vlts: Это довольно широкая тема, но вкратце: в .NET существуют типы значений и ссылочные типы. Типы значений сравниваются по контенту, ссылочные типы - по умолчанию - сравниваются по ссылке, т. Е. Два разных экземпляра с одинаковыми данными * не считаются равными. Однако вы можете переопределить это поведение, переопределив 'object.Equals' в своем классе. –

1

Потому что есть два разных объекта/экземпляры.

1

Оба списка являются отдельными экземплярами, поэтому ReferenceEquals возвращает false, но используется по умолчанию. Вы могли бы реализовать пользовательские IEqualityComparer<IList<object>> для словаря конструктора:

public class ListComparer : IEqualityComparer<IList<object>> 
{ 
    public bool Equals(IList<object> x, IList<object> y) 
    { 
     if (x == null || y == null) return false; 
     return x.SequenceEqual(y); 
    } 

    public int GetHashCode(IList<object> list) 
    { 
     if (list == null) return int.MinValue; 
     int hash = 19; 
     unchecked // Overflow is fine, just wrap 
     { 
      foreach (object obj in list) 
       if(obj != null) 
        hash = hash + obj.GetHashCode(); 
     } 
     return hash; 
    } 
} 

Сейчас он работает, как ожидалось:

var dict = new Dictionary<List<object>, double>(new ListComparer()); 
dict.Add(new List<object>() { "a", "b" }, 3); 
double output = dict[new List<object>() { "a", "b" }]; // 3.0 
Смежные вопросы