2009-04-03 7 views
23

J'ai une suite de fonctions qui ressemblent beaucoup, mais pour une seule ligne, comme les deux suivantes (mais j'ai beaucoup plus d'entre eux):Le passage d'un délégué avec deux paramètres en fonction des paramètres

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

Je pensais à l'aide de délégués pour supprimer cette répétition dans le code d'une manière élégante, qui me aurait permis d'invoquer quelque chose comme:

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

déclarant ainsi un délégué comme ce qui suit:

delegate bool DateComparer(DateTime first, DateTime second); 

et où HowManyDaysInTheFirstPeriod whould être quelque chose comme ce qui suit:

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

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

Malheureusement, le compilateur se plaint que deux paramètres comparateur besoins. Je suis relativement nouveau à C# et frappé un barrage routier ici. Comment voulez-vous résoudre ce problème?

+3

BTW, pour quelqu'un qui dit qu'ils sont assez nouveaux en C#, c'est une utilisation très judicieuse des délégués. Bravo à vous pour repérer la répétition et l'assimiler dans un délégué. –

Répondre

14

Vous êtes presque là! Le paramètre de délégué comparer est comme n'importe quelle autre fonction: Vous devez toujours passer les arguments appropriés pour l'appeler. Dans votre cas, cela va signifier ce changement:

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

(. Notez également que samples devrait probablement samples.Count, comme je l'ai écrit ci-dessus)

4

Vous devez passer le comparateur les deux dates en question. Il est probablement aussi simple s'avance que:

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

Ou vous pouvez les passer dans l'autre sens (à savoir firstDate puis samples[count].Date).

0

Vous devez transmettre les dates comparées au délégué. Donc:

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

Vous pouvez le faire un peu plus simple . Il suffit de fournir la fonction d'un délégué qui extrait tout ce qui doit être comparé d'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++; 
    } 
} 

et il peut alors être appelé en tant que tel:

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

La syntaxe (dt) => dt.year peut être nouveau pour vous, mais il est une manière plus propre d'écrire "un délégué anonyme qui prend un objet dt d'un type générique, et renvoie dt.year". Vous pourriez écrire un délégué à l'ancienne, mais c'est plus agréable.:)

Nous pouvons faire un peu plus général que si, en ajoutant un autre paramètre de type générique:

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) 

Comme d'habitude cependant, LINQ offre une plus belle encore autre:

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

Je pense que la réponse de jalf doit être légèrement modifiée pour s'adapter à l'usage 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; 
} 

Appeler en utilisant:

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