传递具有两个参数的委托作为参数函数

时间:2009-04-03 11:57:51

标签: c# delegates

我有一系列看起来非常相似的函数,但对于一行,如下面两行(但我还有更多):

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++;
    }
}

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

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

5 个答案:

答案 0 :(得分:14)

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

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

(另请注意,samples可能应为samples.Count,如上所述。)

答案 1 :(得分:6)

你可以做得更简单一些。简单地为函数提供一个委托,它从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) => 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)
}

答案 2 :(得分:4)

您需要通过比较两个有问题的日期。它可能就像:

一样简单
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)。

答案 3 :(得分:1)

我认为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; });

答案 4 :(得分:0)

您需要传递与委托进行比较的日期。所以:

comparer(samples[count].Date, firstDate)