2016-11-12 4 views
-1

Я пытаюсь использовать Linq для преобразования списка в словарь. Я смог получить правильные результаты с анонимными типами в качестве ключей, но не с конкретными типами. Пожалуйста, см коды отрезали ниже:Linq ToDictionary anonymous verses конкретных типов

 // Works. Produces 329 entries in dictionary, as expected. 
     var groupByMonth = 
      from e in list 
      group e by new { e.chk.Month, e.chk.Year } into g 
      select new { month = g.Key, rates = g.ToList() }; 
     var monnthlyRates = groupByMonth.ToList(); 
     var monnthlyRatesDict = groupByMonth.ToDictionary(t => t.month, t => t.rates); 

     // IS NOT WORKING. Produces 30K entries in dictionary; same num as in the list. 
     // i.e. the grouping does not happen 
     var groupByMonth2 = 
      from e in list 
      group e by new MonthYear { Month = e.chk.Month, Year = e.chk.Year } into g 
      select new MonthYearRates { MonthYear = g.Key, Rates = g.ToList()}; 
     var monnthlyRatesDict2 = groupByMonth2.ToDictionary(t => t.MonthYear, t => t.Rates); 

     // Works. Dictionary has 329 entries 
     var groupByMonth3 = 
      from e in list 
      group e by new DateTime(e.chk.Year, e.chk.Month, 1) into g 
      select new MonthYearRates2 { MonthYear = g.Key, Rates = g.ToList() }; 
     var monnthlyRatesDict3 = groupByMonth3.ToDictionary(t => t.MonthYear, t => t.Rates); 

Я попытался решить эту проблему путем внедрения IComparer и/или IComparable в конкретном типе; безрезультатно

class MonthYear : IComparer 
// class MonthYear : IComparable, IComparer 
{ 
    public MonthYear() 
    { 
    } 
    public MonthYear(int month, int year) 
    { 
     Month = month; 
     Year = year; 
    } 
    int IComparer.Compare(Object x, Object y) 
    { 
     MonthYear xo = (MonthYear)x; 
     MonthYear yo = (MonthYear)y; 

     if (yo.Year > xo.Year) 
      return 1; 
     else if (yo.Year < xo.Year) 
      return -1; 
     else 
     { 
      if (yo.Month > xo.Month) 
       return 1; 
      else if (yo.Month < xo.Month) 
       return -1; 
      else 
       return 0; 
     } 
    } 

    //int IComparable.CompareTo(object obj) 
    //{ 
    // MonthYear o = (MonthYear)obj; 

    // if (Year > o.Year) 
    //  return 1; 
    // else if (Year < o.Year) 
    //  return -1; 
    // else 
    // { 
    //  if (Month > o.Month) 
    //   return 1; 
    //  else if (Month < o.Month) 
    //   return -1; 
    //  else 
    //   return 0; 
    // } 
    //} 
    public int Month; 
    public int Year; 
} 

Я понимаю, что Lookup лучше подходит для этого словаря; Я буду искать Lookup, как только я закончил с любыми анонимными типами.

+0

Анонимные типы используют структурное равенство, которое посредством отражения проверяет все свойства типа, конкретные классы используют объект/ссылку равенство по умолчанию. Создайте собственный класс, который реализует тип 'IEqualityComparer '. то есть не IComparer и как отдельный класс. Ie 'class MonthYearEqualityComparer: IEqualityComparer {...}' и передать это методу 'ToDictionary' в качестве последнего параметра – pinkfloydx33

+0

Альтернативно, если вы можете сделать MonthYear неизменной' struct' вместо этого, вы получите структурное равенство без какой-либо работы над ваша часть (опять же, сделанная по умолчанию с использованием отражения), хотя это не может быть жизнеспособным вариантом. – pinkfloydx33

ответ

2

Словарь использует Object.Equals и Object.GetHashCode по умолчанию для проверки ключей. Вы не хотите, чтобы IComparable (IComparable около заказывал вещи, не проверяя, равны ли они. Технически, только потому, что CompareTo возвращает ноль, не означает, что 2 объекта одинаковы). Вам необходимо переопределить Object.GetHashCode() и Object.Equals(object otherObject), которые анонимные типы делают автоматически, поэтому они работают для вас здесь.

Равновесие должно быть простым, просто убедитесь, что объект правильный, затем проверьте два поля для равенства. Для GetHashCode есть хорошие ответы в другом месте на StackOverflow (получение этого может быть немного сложным), как здесь: What is the best algorithm for an overridden System.Object.GetHashCode?

+0

Точно. Объекты-контейнеры, ключи, будут разными объектами. Они НЕ были бы объектами равными; но я хочу что-то равное ценности; объекты могут быть разными, но значения, которые они удерживают, равны. Woudn't overriding. Equal, чтобы выдать эквивалентность стоимости, а не эквивалентность объектов, приводит к проблемам в другом месте? – Amit

+0

И я реализовал .Equals; что все еще не исправить проблему для меня – Amit

+0

Проблема решена, когда я реализовал функции, указанные вами. Но я сомневаюсь, что это правильная вещь: замена эквивалентности объекта эквивалентностью объекта. – Amit

 Смежные вопросы

  • Нет связанных вопросов^_^