0

I have two similar functions I hope to refactor to remove duplication:

IEnumerable<TotalType> GetTotalForMonths(string id, DateTime lastTotalDate)
{
    for (int i = 0; lastTotalDate.AddMonths(i + 1) <= DateTime.Now; i++)
    {
        var totalStartDate = new DateTime(lastTotalDate.AddMonths(i).Year, lastTotalDate.AddMonths(i).Month, 1);
        var totalEndDate = totalStartDate.AddMonths(1);
        var total = this.GetTotal(id, totalStartDate, totalEndDate);
        yield return new TotalType(id, total, new TimeInterval(totalStartDate, totalEndDate));
    }
}

The other does the same thing for days. I hope to pass in a delegate to generic-ize the particular duration (days, months, etc). I tried passing in Func<DateTime, DateTime> addTime, which works well, except that I don't want to specify addTime's arg value.

Suggestions?

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
Lachlan
  • 901
  • 1
  • 7
  • 20

3 Answers3

2

I'm not sure if I understood your question correctly, but if you want to pass AddMonth method as an argument, without specifying the receiver object, you can construct a lambda:

GetTotal(id, lastDate, (dt, num) => dt.AddMonth(num))

to call the "genericized" function.

You need to declare the function as:

IEnumerable<TotalType> GetTotal(string id, DateTime lastTotalDate,
   Func<DateTime, int, DateTime> adder)
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
2
var byMonths = GetTotal(123, yourDate, (d, i) => d.AddMonths(i));

var byDays = GetTotal(456, anotherDate, (d, i) => d.AddDays(i));

// ...

IEnumerable<TotalType> GetTotal(
    string id, DateTime lastTotalDate, Func<DateTime, int, DateTime> adder)
{
    for (int i = 0; adder(lastTotalDate, i + 1) <= DateTime.Now; i++)
    {
        var temp = adder(lastTotalDate, i);
        var totalStartDate = new DateTime(temp.Year, temp.Month, 1);
        var totalEndDate = adder(totalStartDate, 1);
        var total = this.GetTotal(id, totalStartDate, totalEndDate);
        var interval = new TimeInterval(totalStartDate, totalEndDate);

        yield return new TotalType(id, total, interval);
    }
}
LukeH
  • 263,068
  • 57
  • 365
  • 409
0

What you're seeking to do is called "Currying". I have a pattern which I use in vb.net for that purpose; I'm not sure it's the best pattern, but it should be adaptable to C# without too much trouble. Note that while using lambda expressions will limit your ability to use edit-and-continue, use of a curry factory will pose no such restriction.

Here's a link to my question: What is the best pattern to curry delegate parameters (using .NET 2.0 or later)?

That should translate nicely into C#; any time you see parentheses starting with "(Of", replace them with angle brackets; "ByRef Foo As Bar" and "Dim Foo As Bar" both become "Bar Foo".

Community
  • 1
  • 1
supercat
  • 77,689
  • 9
  • 166
  • 211