2

I have a struct which I want to add static methods to. Yes, you guessed right I'm talking about Datetime.

It's a pretty typical requirement to add MyCustomParse. It happens to return Datetime?, so it's not a constructor, but it's in that area, a static method that returns an instance. The content of this method has already been written and currently happy lives as a instance method of a class that uses it. I want to bring it out of that class so I can use it elsewhere.

Traditionally I would put it in a helper class (which is what I've done here), but apparently they're evil.

What I really want to do is tie Datetime.MyCustomParse(mystring). But the only way I can see is to make a new struct that composes Datetime. I then add in my method, write the implicit conversions and then put in all the other Datetime methods etc. This would be a pain to code (Being verbose also causes problems wrt xml docs and naive code coverage metrics, if that counts for anything).

I have considered extension methods, but I don't think the methods make sense on instances.

What is the strict OO position? Do I get a pass on writing methods that should belong to classes in separate helper classes when I want to extend structs in this fashion?

What is the pragmatic position (I'm not saying OO isn't pragmatic), is this code you would write, or have I missed a trick?

internal static class DateTimeHelper
{

    public static DateTime? MyCustomParse(string utcDateTimeText, string[] formats)
    {
        DateTime utcDateTime;
        if (DateTime.TryParseExact(utcDateTimeText, formats, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out utcDateTime))
        {
            return utcDateTime;
        }

        return null;
    }
}

PS I know there are more nuanced views on helper classes, but I still feel I need to justify my use here.

6
  • Umm what? DateTime already has a Parse...
    – Telastyn
    Aug 7, 2014 at 13:08
  • @Telastyn. Yeah, I can see how that's unclear. I would have to rename it if I stuck it in with DateTime. I've named to to MyCustomParse to prevent confusion.
    – Nathan
    Aug 7, 2014 at 13:11
  • 1
    Helper classes are not evil. The article mentioned uses logical fallacies. So, really it is NOT the subject of discussion. But still I'll give an example. If you want to extend the functionality for the non-extendable classes, for example, String, the helper classes are the only solution. Oh, since Java 8 the interfaces can serve, too. It is only one example, but there are many of them.
    – Gangnus
    Aug 7, 2014 at 13:55
  • 1
    Helpers as a place to shove code that doesn't fit anywhere else could be described as less than ideal (not sure "evil" works here). That is typically an indicator of a bad design. Classes that are full of static methods (as the author defines helpers) are not bad, however. They are quite useful in creational design patterns, but not strictly necessary.
    – user22815
    Aug 7, 2014 at 21:22
  • 1
    There is nothing wrong with using a static helper method if it is a pure function with no dependencies that does not need any extensibility. Yours is a perfect case for it.
    – John Wu
    Sep 11, 2022 at 17:58

3 Answers 3

3

What is the strict OO position?

"strict" is undefined in OO space?

What is the pragmatic position? I want to bring it out of that class so I can use it elsewhere. The content of this method has already been written and currently happy lives as a instance method of a class that uses it.

OO Rationalization

Well, one approach may be to think about creational design patterns. I see this as counterpoint to the "helper class" idea. I see the "helper" as a smorgasbord - incoherent in terms of domain object design.

But a Factory, Builder, etc. composes behavior within an object- a domain-coherent thing. How is this different from a helper class? Intent.

OO Pragmatism meets Intent

Refactor to turn the method into a delegate. You can declare the delegate at the namespace level if necessary.

Write a instance-building something that registers/binds/whatever the delegate method. I expect the method's implementation will be inside this something.

Somthing's purpose in life is to instantiate fully-realized objects of the class/struct. Something does not contain those "random" type-specific (but not instance-owned) helper methods.

And because of intent we do not want the pragmatic approach of a class static method - which you have already dismissed.

3
  • An object is overkill for his example. He doesn't need any internal state, he just needs 2 inputs in and 1 output out.
    – Doval
    Aug 7, 2014 at 19:24
  • So... Rename DateTimeHelper to DateTimeFactory?
    – Nathan
    Aug 7, 2014 at 21:18
  • 2
    @NathanCooper Essentially, your DateTimeHelper is acting exactly like a DateTimeFactory would, so here, yes, just rename it, so that the class's intent is clearer. If your class had more, unrelated helpers on it, you would instead split off the factory method into a factory class. The problem with "helpers" is that often they do not adhere to Single Responsibility, whereas a factory has the single responsibility of object construction. Some (myself included) prefer factory instances, but some (myself included) will make static factory methods instead. YMMV.
    – cbojar
    Aug 8, 2014 at 0:58
3

Why not use an extension method?

public static class DateTimeExtensions
{
   public static DateTime? AsDateTime(this string value, string[] formats)
   {
       DateTime utcDateTime;

       if (DateTime.TryParseExact(utcDateTimeText, formats,CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out utcDateTime))
       {
            return utcDateTime;
       }

       return null;
   }
 }

This will extend the string type adding the method AsDateTime.

string[] formats= {"M/d/yyyy h:mm:ss tt", "MM/dd/yyyy h:mm:ss tt" }; 
string unParsedDateTime = "05/01/2009 6:32:05 PM";

DateTime parsed = unParsedDateTime.AsDateTime(formats);
// or  
parsed = "05/01/2009 6:32:05 PM".AsDateTime(formats);
1
  • This answer is code-only. Code-only answers are considered bad quality here. Could you elaborate about how your solution works ? Aug 7, 2014 at 21:13
2

Helper classes can be an organizational anti-pattern when you have some generic Helpers file where you dump every single miscellaneous static function all your projects have ever used. Don't do that. Regardless, they're not evil. A static method is the right place to put some frequently-used computation that don't need to look at any object's private state. Functions like MyCustomParse don't really belong in any class - it can get the job done without looking at anyone's implementation details, so it's not part of any given abstraction. It's just one of the many ways you could choose to convert between two representations of dates.

Creating wrapper classes just because it "feels" more OOP if the function is attached to an instance of something will just cause you and future code maintainers headaches. Besides having to convert back and forth between the wrapped and wrapper types, you'll either have to edit the wrapper or create new ones every time you need a new helper method - and in the latter case you'll have even more conversions. It doesn't scale.

Extension methods can let you use helper functions with the syntax of method calls, which can be nice for Intellisense or when a function call looks better in infix form. This is pure syntax sugar; semantically there's not much of a difference between extension methods and regular static methods.

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.