可为空的 DateTime 扩展抛出 'does not contain a definition' 异常

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

在下面的代码中:

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;
    }
}

这一行 DateTime cleanDate = DateTime.Now.ToCleanDateTime(); 抛出以下异常。

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

如果我在扩展方法中评论 DateTime public static DateTime ToCleanDateTime(this DateTime dt) 不会抛出错误。

谁能启发我:

  1. 为什么抛出这个错误(除了显而易见的)?
  2. 有没有办法将这两个扩展组合成一个方法?

我以某种方式期望 public static DateTime? ToCleanDateTime(this DateTime? dt) 能够同时处理 DateTimeDateTime?

这不是抛出的异常,而是编译器错误。前者发生在运行时,后者发生在编译时。这是一个重要的区别。

您收到此错误是因为编译器找不到接受 DateTime 的扩展方法,只有接受 DateTime? 的扩展方法。这些是完全不同的类型。 Nullable<T>T 没有任何继承关系,因此您不能为 Nullable<T> 重载接受 T,反之亦然。

您可以通过让一个方法调用另一个方法来组合这些方法:

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;
    }
}

或者您可以只使用 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 而不管输入的 Kind

如果 dt 的数据类型是 DateTime?,您可以使用 dt.value.Month 和 dt.Value.Year 等来获取数据