Reputation: 2973
I have a sequence of functions that look very similar but for a single line, like the following two (but I have many more of them):
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;
}
I was thinking about using delegates to remove this repetition in code in some elegant way, that would have allowed me to invoke something like:
HowManyDaysInTheFirstPeriod(
samples,
delegate(DateTime d1, DateTime d2) { return d1.Month == d2.Month; });
thereby declaring a delegate like the following:
delegate bool DateComparer(DateTime first, DateTime second);
and where HowManyDaysInTheFirstPeriod whould be something like the following:
private static int HowManySamplesInFirstPeriod
IList<T> samples,
DateComparer comparer)
{
DateTime firstDate = samples[0].Date;
int count = 0;
while (count < samples.Count && comparer())
{
count++;
}
}
Unfortunately, the compiler complains that comparer needs two parameters.
I am relatively new to C# and hit a road-block here. How would you solve this?
Upvotes: 23
Views: 46318
Reputation: 178820
You need to pass the dates being compared to the delegate. So:
comparer(samples[count].Date, firstDate)
Upvotes: 0
Reputation: 30734
I think jalf's answer needs to be modified slightly to fit the original usage:
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;
}
Call using:
HowManyDaysInTheFirstPeriod(samples, (d1, d2) = > { return d1.Month == d2.Month; });
HowManyDaysInTheFirstPeriod(samples, (d1, d2) = > { return d1.Year == d2.Year; });
Upvotes: 1
Reputation: 248269
You can do it a bit simpler. Simply provide the function a delegate which extracts whatever should be compared from a 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++;
}
}
and it can then be called as such:
HowManySamplesInFirstPeriod(samples, (dt) => dt.Year); // to get the year
HowManySamplesInFirstPeriod(samples, (dt) => dt.Month); // to get the month
The (dt) => dt.year
syntax may be new to you, but it's a cleaner way of writing "an anonymous delegate which takes an object dt of some generic type, and returns dt.year".
You could write an old-fashioned delegate instead, but this is nicer. :)
We can make it a bit more general than that though, by adding another generic type parameter:
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)
As usual though, LINQ provides a nicer still alternative:
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)
}
Upvotes: 6
Reputation: 311735
You're almost there! The comparer
delegate parameter is just like any other function: You still need to pass the appropriate arguments to invoke it. In your case, that's going to mean this change:
while (count < samples.Count && comparer(samples[count].Date, firstDate))
{
count++;
}
(Also, note that samples
should probably be samples.Count
, as I have written above.)
Upvotes: 14
Reputation: 1503529
You need to pass the comparer the two dates in question. It's probably juts as simple as:
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++;
}
}
Or you may want to pass them the other way round (i.e. firstDate
and then samples[count].Date
).
Upvotes: 4