Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nullable DateTime extension throws 'does not contain a definition' exception

In the code below:

void Main()
{
    DateTime cleanDate = DateTime.Now.ToCleanDateTime();    
    DateTime? nullableCleanDate = DateTime.Now;
    nullableCleanDate = nullableCleanDate.ToCleanDateTime();

    cleanDate.Dump();
    nullableCleanDate.Dump();
}

public static class Extensions
{
    //public static DateTime ToCleanDateTime(this DateTime dt)
    //{
    //  dt = new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0, 0);
    //  return dt;
    //}

    public static DateTime? ToCleanDateTime(this DateTime? dt)
    {
        if (dt.HasValue)
            dt = new DateTime(dt.Value.Year, dt.Value.Month, dt.Value.Day, 0, 0, 0, 0);
        return dt;
    }
}

This line DateTime cleanDate = DateTime.Now.ToCleanDateTime(); throws following exception.

'System.DateTime' does not contain a definition for 'ToCleanDateTime' and the best extension method overload 'Extensions.ToCleanDateTime(System.DateTime?)' has some invalid arguments

If I comment in extension method for DateTime public static DateTime ToCleanDateTime(this DateTime dt) error is not thrown.

Could anyone enlighten me with:

  1. Why is this error thrown (aside from the obvious)?
  2. Is there a way to combine these two extensions into single method?

I somehow expected public static DateTime? ToCleanDateTime(this DateTime? dt) to handle both DateTime and DateTime?.

like image 269
CrnaStena Avatar asked May 28 '15 18:05

CrnaStena


1 Answers

That's not an exception that's thrown, that's a compiler error. The former happens at runtime, the latter at compile time. It's an important difference.

You get this error because the compiler can't find an extension method accepting a DateTime, only one with a DateTime?. Those are entirely different types. Nullable<T> has no inheritance relation whatsoever to T, so you can't make an overload for Nullable<T> accept a T, nor vice versa.

You can combine the methods by letting one call the other:

public static class Extensions
{
    public static DateTime ToCleanDateTime(this DateTime dt)
    {
      return new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0, 0);      
    }

    public static DateTime? ToCleanDateTime(this DateTime? dt)
    {
        if (dt.HasValue)
        {
            return dt.Value.ToCleanDateTime();
        }
        return dt;
    }
}

Or you can just use DateTime.Date, which returns the same as your extension method and preserves the Kind, as opposed to the above code with which Kind will be Unspecified regardless the input's Kind.

like image 180
CodeCaster Avatar answered Oct 31 '22 22:10

CodeCaster