Подтвердить что ты не робот

Передача делегата с двумя параметрами в качестве функции параметра

У меня есть последовательность функций, которые выглядят очень похожими, но для одной строки, как и следующие две (но у меня их много):

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

К сожалению, компилятор жалуется, что для сравнения нужны два параметра.

Я относительно новичок в С# и попал в дорожный блок здесь. Как бы вы решили это?

4b9b3361

Ответ 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) => dt.year может быть новым для вас, но это более чистый способ записи "анонимного делегата, который принимает объект dt некоторого родового типа и возвращает dt.year". Вместо этого вы могли бы написать старомодного делегата, но это лучше.:)

Мы можем сделать это немного более общим, чем это, добавив еще один типовой параметр:

private static int HowManySamplesInFirstPeriod<T, U>
    IList<T> samples,
    Func<DateTime, U> f // Let 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 answer нужно немного изменить, чтобы соответствовать оригинальному использованию:

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)