【问题标题】:Passing a delegate with two parameters as a parameter function将带有两个参数的委托作为参数函数传递
【发布时间】:2012-06-11 23:26:58
【问题描述】:

我有一系列看起来非常相似但只有一行的函数,例如以下两个(但我还有更多):

private static int HowManyHoursInTheFirstYear(IList<T> samples)
{
    DateTime firstDate = samples[0].Date;
    int count = 0;

    while (count < samples.Count && 
          samples[count].Date.Year == firstDate.Year)
    {
        count++;
    }

    return count;
}


private static int HowManyDaysInTheFirstMonth(IList<T> samples)
{
    DateTime firstDate = samples[0].Date;
    int count = 0;

    while (count < samples.Count && 
           samples[count].Date.Month == firstDate.Month) // <--- only change!
        count++;
    }

    return count;
}

我正在考虑使用委托以某种优雅的方式删除代码中的这种重复,这将允许我调用类似的东西:

HowManyDaysInTheFirstPeriod(
    samples,
    delegate(DateTime d1, DateTime d2) { return d1.Month == d2.Month; });

从而声明如下委托:

delegate bool DateComparer(DateTime first, DateTime second);

HowManyDaysInTheFirstPeriod 应该类似于以下内容:

private static int HowManySamplesInFirstPeriod
    IList<T> samples,
    DateComparer comparer)
{
    DateTime firstDate = samples[0].Date;
    int count = 0;

    while (count < samples.Count && comparer())
    {
        count++;
    }
}

不幸的是,编译器抱怨比较器需要两个参数。

我对 C# 比较陌生,在这里遇到了障碍。 你会如何解决这个问题?

【问题讨论】:

  • 顺便说一句,对于那些说他们对 C# 很陌生的人来说,这是对委托的非常明智的使用。感谢您发现重复并将其分解到委托中。

标签: c# delegates


【解决方案1】:

你快到了! comparer 委托参数就像任何其他函数一样:您仍然需要传递适当的参数来调用它。在您的情况下,这将意味着这种变化:

while (count < samples.Count && comparer(samples[count].Date, firstDate))
{
    count++;
}

(另外,请注意samples 可能应该是samples.Count,正如我在上面所写的。)

【讨论】:

    【解决方案2】:

    你可以简单一点。只需为函数提供一个委托,该委托从 DateTime 中提取应比较的任何内容:

    private static int HowManySamplesInFirstPeriod<T>
        IList<T> samples,
        Func<DateTime, int> f // a function which takes a DateTime, and returns some number
    {
        DateTime firstDate = samples[0].Date;
        int count = 0;
    
        while (count < samples && f(samples[count].Date) == f(firstDate))
        {
            count++;
        }
    }
    

    然后可以这样调用它:

    HowManySamplesInFirstPeriod(samples, (dt) => dt.Year); // to get the year
    HowManySamplesInFirstPeriod(samples, (dt) => dt.Month); // to get the month
    

    (dt) =&gt; dt.year 语法对您来说可能是新的,但它是一种更简洁的编写方式:“匿名委托接受某种通用类型的对象 dt,并返回 dt.year”。 你可以写一个老式的委托,但这更好。 :)

    我们可以通过添加另一个泛型类型参数使其更通用:

    private static int HowManySamplesInFirstPeriod<T, U>
        IList<T> samples,
        Func<DateTime, U> f // Let's generalize it a bit, since the function may return something other than int (some of the DateTime members return doubles, as I recall)
    

    尽管如此,LINQ 提供了一个更好的替代方案:

    private static int HowManySamplesInFirstPeriod<T>
        IList<T> samples,
        Func<DateTime, int> f)
    {
      var firstVal = f(samples.First().Date);
      return samples.Count(dt => f(dt.Date) = firstVal)
    }
    

    【讨论】:

      【解决方案3】:

      您需要将有问题的两个日期传递给比较器。大概就这么简单:

      private static int HowManySamplesInFirstPeriod
          IList<T> samples,
          DateComparer comparer)
      {
          DateTime firstDate = samples[0].Date;
          int count = 0;
      
          while (count < samples.Count 
                 && comparer(samples[count].Date, firstDate))
          {
              count++;
          }
      }
      

      或者您可能想反过来传递它们(即firstDate 然后samples[count].Date)。

      【讨论】:

        【解决方案4】:

        我认为 jalf 的回答需要稍作修改以适应原始用法:

        private static int HowManyHoursInTheFirstYear(IList<DateTime> samples, Func<DateTime, DateTime, bool> comparer) 
        { 
            DateTime firstDate = samples[0].Date; 
            int count = 0;
            while (count < samples.Count && comparer(samples[count], firstDate) ) {
                count++;
            } 
            return count; 
        }
        

        调用方式:

        HowManyDaysInTheFirstPeriod(samples, (d1, d2) = > { return d1.Month == d2.Month; });
        HowManyDaysInTheFirstPeriod(samples, (d1, d2) = > { return d1.Year == d2.Year; });
        

        【讨论】:

          【解决方案5】:

          您需要将要比较的日期传递给委托人。所以:

          comparer(samples[count].Date, firstDate)
          

          【讨论】:

            猜你喜欢
            • 2013-11-17
            • 1970-01-01
            • 2011-05-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多