2009-04-03 17 views
23

tengo una secuencia de funciones que son muy similares, pero para una sola línea, al igual que los dos siguientes (pero tengo muchos más de ellos):Pasando un delegado con dos parámetros en función de parámetros

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

estaba pensando acerca del uso de los delegados para eliminar esta repetición en el código de alguna manera elegante, que habría permitido que yo invoco algo como:

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

declarando así como un delegado lo siguiente:

delegate bool DateComparer(DateTime first, DateTime second); 

y donde HowManyDaysInTheFirstPeriod whould ser algo como lo siguiente:

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

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

Por desgracia, el compilador se queja de que comparador necesita dos parámetros.

Soy relativamente nuevo en C# y toco un bloqueo de carretera aquí. ¿Cómo resolverías esto?

+3

BTW, para alguien que dice que es bastante nuevo en C#, este es un uso muy razonable de los delegados. Felicitaciones a usted por detectar la repetición y factorizarlo en un delegado. –

Respuesta

14

¡Ya casi está allí! El parámetro delegado comparer es como cualquier otra función: Aún necesita pasar los argumentos apropiados para invocarlo. En su caso, eso va a significar este cambio:

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

(. Además, tenga en cuenta que samples probablemente debería ser samples.Count, como he escrito anteriormente)

4

Debe pasar al comparador las dos fechas en cuestión. Es probable que se adentra tan simple como:

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

O es posible que desee para pasarlos al revés (es decir firstDate y luego samples[count].Date).

0

Debe pasar las fechas que se comparan con el delegado. Entonces:

comparer(samples[count].Date, firstDate) 
6

Usted puede hacer que sea un poco más sencillo . Sólo es necesario que la función de un delegado que extrae lo que debe compararse de un 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++; 
    } 
} 

y puede entonces ser llamado como tal:

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

La sintaxis (dt) => dt.year puede ser nuevo para usted, pero es una forma más limpia de escribir "un delegado anónimo que toma un objeto dt de algún tipo genérico y devuelve dt.year". En su lugar, podría escribir a un delegado pasado de moda, pero esto es más agradable.:)

Nos puede que sea un poco más general que, sin embargo, mediante la adición de otro parámetro de tipo genérico:

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) 

Como de costumbre, sin embargo, LINQ proporciona una mejor alternativa sigue:

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) 
} 
1

Creo que la respuesta de jalf debe modificarse ligeramente para adaptarse al uso original:

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

Llamada usando:

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