Linq ToDictionary 匿名与具体类型

Linq ToDictionary anonymous versus concrete types

我正在尝试使用 Linq 将列表转换为字典。我已经能够使用匿名类型作为键获得正确的结果,但不能使用具体类型。请参阅下面的代码片段:

        // 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 and/or 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。

字典默认使用 Object.Equals 和 Object.GetHashCode 来检查键。您不需要 IComparable(IComparable 是关于 排序 的东西,而不是检查它们是否相等。从技术上讲,仅仅因为 CompareTo returns 为零,并不意味着 2 个对象是相同)。您需要覆盖 Object.GetHashCode()Object.Equals(object otherObject) ,匿名类型会自动执行,这就是它们在这里为您工作的原因。

相等应该很简单,只需确保对象的类型正确,然后检查两个字段是否相等。对于 GetHashCode,在 Whosebug 的其他地方有一些很好的答案(获得它可能有点棘手),就像这里:What is the best algorithm for an overridden System.Object.GetHashCode?