1
\$\begingroup\$

I really like functional programming in C#, it gives you a lot of flexibility. I am wondering if it is the right idea to use functions instead of helper methods, and to make the code more readable.

So here is what I want, I have a method that needs to find Saturday and do something with it:

public void SomeMethod()
{
    var saturday = DateTime.Today;
    while (saturday.DayOfWeek != DayOfWeek.Saturday)
            saturday = saturday.AddDays(-1);

    //rest of the code
}

The problem I am having with this code is readability. I have to scan through 3 lines of code to understand that it needs to find Saturday. Plus seeing var saturday = DateTime.Today;, it really bugs my eyes.

Of course I can write a helper method

private DateTime GetSaturday()
{
    var saturday = DateTime.Today;
    while (saturday.DayOfWeek != DayOfWeek.Saturday)
            saturday = saturday.AddDays(-1);
    return saturday;
}

Now I know exactly what the method does but my problem now is that I know that I won't be calling this method anywhere in the class so it kind of pollutes my class.

So here we are at my favorite:

public void SomeMethod()
{
    Func<DateTime> GetSaturdayFunc = () =>
        {
            var date = DateTime.Today;
            while (date.DayOfWeek != DayOfWeek.Saturday)
                date = date.AddDays(-1);
            return date;
        };

   var saturday = GetSaturdayFunc();
   //rest of the code
}

Although it's a bit more code now my class is not polluted with a lot of utility methods and it is more readable.

What do you think? Is this a good way, are there any better ways?

EDIT

I could also create an extension method which in this case would be appropriate, something like

DateTime.Saturday() 

but that's not what I am referring to in my question. I am asking if it is a good practice to wrap a portion of the code as a function inside that method (since that peace of the code will only be used inside that method and might not apply anywhere else), just for readability purposes.

\$\endgroup\$
7
  • \$\begingroup\$ Why are the proposed solutions not acceptable? The best practice for this behavior is a utility function or an extension method and you seem to be excluding both of those from the pool of acceptable answers. \$\endgroup\$
    – alc
    Commented Aug 2, 2013 at 21:46
  • \$\begingroup\$ If anything, the anonymous method creates more confusion than your original implementation. Especially if you only use the function once. \$\endgroup\$
    – Moop
    Commented Aug 2, 2013 at 21:48
  • \$\begingroup\$ Exactly. Anonymous methods are great for things like auto-generated event handlers or LINQ expressions, but using them to hide behavior that you freely admit shouldn't be part of the class that it's within seems like an anti-pattern to me. \$\endgroup\$
    – alc
    Commented Aug 2, 2013 at 21:52
  • \$\begingroup\$ I am not saying those are not acceptable, my question is usage of function instead of utility/helper/other methods in ways of organizing code. I just want to know what other think about it. \$\endgroup\$ Commented Aug 2, 2013 at 21:55
  • \$\begingroup\$ And I am not saying that the code does not belong to the class, I am saying that only a single method in that class will be using that code. Something like closures in javascript. \$\endgroup\$ Commented Aug 2, 2013 at 22:00

4 Answers 4

2
\$\begingroup\$

I actually think I slightly disagree with the other answers in this situation. As you, others have mentioned I see three possible solutions (although there may be others)

  1. Create a local Func()
  2. Create a method on some sort of utilitly class or on a specific class for dealing with Date manipulation i.e Calendar
  3. Create a private method to the class (as it won't be used anywhere else anyway)
  4. Create an extension method

Now from your question you state that you do not intend to use the method anywhere else. Your example tends one to think it would be beneficial in other situations as it is fairly generic. In that situation I would be leaning towards an extension method as others have pointed out.

However I often find myself in the situation where a block of code will be repeated in a function and only the variables passed in will vary dependant on local switches etc In this situation I think it's perfectly reasonable to create a local delegate and use that in the function only.

So, to summarize. Yes I think it's acceptable. In your example, probably not, but in situations where the block of code is local only to that method and you know that is the case, then yes. You can always refactor later!

\$\endgroup\$
2
  • \$\begingroup\$ Yes, that was kind of what I wanted to hear :) I probably choose a bad chunk of code for an example, since it is fairly generic and extension method is a perfect candidate \$\endgroup\$ Commented Aug 3, 2013 at 22:04
  • \$\begingroup\$ @DZL I don't know if you had a real example but you may have had better feed back if you posted that instead? Otherwise I wonder if programmers might have been a better fit??? Not sure but glad to offer my opinion anyway :) \$\endgroup\$
    – dreza
    Commented Aug 4, 2013 at 2:18
5
\$\begingroup\$

This is a perfect use case for an extension method. It gives maximum readability to your business code, and makes the method available on any DateTime object.

//Test
class Program
{
    static void Main(string[] args)
    {
        Console.Write(DateTime.Today.MostRecent(DayOfWeek.Saturday));
        Console.Read();
    }
}
//Extensions
public static class DateTimeExtensions
{
    public static DateTime MostRecent(this DateTime date, DayOfWeek dayOfWeek)
    {
        var day = date.Date;
        while (day.DayOfWeek != dayOfWeek)
            day = day.AddDays(-1);
        return day;

    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ As the OP states that he "won't be calling this method anywhere", making it an extension method is overkill at best. \$\endgroup\$
    – ctrucza
    Commented Aug 3, 2013 at 21:48
2
\$\begingroup\$

You could try create a utility function elsewhere in your solution ...

public static class DateUtils
{
    public static DateTime MostRecent(DayOfWeek weekDay)
    {
        var date = DateTime.Today;
        while (date.DayOfWeek != weekDay)
            date = date.AddDays(-1);
        return date;
    }
}

... and then use it later in your code ...

public void SomeMethod()
{
    var saturday = DateUtils.MostRecent(DayOfWeek.Saturday);
    // rest of code
}

... which has the benefits of being reusable and in an appropriate object structure.

\$\endgroup\$
4
  • \$\begingroup\$ The better solution would be to create an extension method and call it like DateTime.Saturday() \$\endgroup\$ Commented Aug 2, 2013 at 20:48
  • 4
    \$\begingroup\$ @DZL: I don't think a .Saturday() extension method is a "better solution". Hard-coding in a date like that seems arbitrary, especially since it logically follows that you'd have to have .Sunday(), .Monday(), etc. next. Moreover, .Saturday() says nothing about how it's the most-recent Saturday, just that it's a Saturday. \$\endgroup\$
    – alc
    Commented Aug 2, 2013 at 21:50
  • \$\begingroup\$ I agree, I was refering to that as a pseudo code, not the real implementation. I was just saying that the extension method for me is a better idea. \$\endgroup\$ Commented Aug 2, 2013 at 22:07
  • 1
    \$\begingroup\$ Being reusable is not an advantage in the OP's case, as he does not intend to call this code from anywhere else. \$\endgroup\$
    – ctrucza
    Commented Aug 3, 2013 at 21:49
2
\$\begingroup\$

I would use an extension method over an utility function.

namespace DateTime.Extensions
{
    public static class DateTimeExtensions
    {
        public static DateTime Previous(this DateTime now, DayOfWeek day)
        {
           do {
              now = now.AddDays(-1);
           } while (now.DayOfWeek != day)

           return now;
        }
    }
}

and its use:

public void SomeMethod()
{
    var saturday = DateTime.Today.Previous(DayofWeek.Saturday);

    //rest of the code
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.