【问题标题】:Extension method resolution with nullable value type params具有可为空值类型参数的扩展方法解析
【发布时间】:2014-02-25 13:41:21
【问题描述】:
public static class Extension
{
    public static void Test(this DateTime? dt)
    {
    }
}


void Main()
{
    var now = DateTime.Now;
    Extension.Test(now); // ok
    now.Test(); // compile time error
}

我只是好奇,为什么编译器在作为扩展调用时无法解析相同的方法?

【问题讨论】:

  • 只要看到错误,你的好奇心就会消失。
  • 我正要问这个问题,想知道这是否是编译器错误。 C# 语言有提交错误报告的地方吗?

标签: c# compiler-construction overloading extension-methods


【解决方案1】:

DateTime 明确为 not convertible to Nullable<DateTime>

C# 规范,7.6.5.2 扩展方法调用:

如果满足以下条件,则扩展方法是合格的:

  • 如上所示,当作为静态方法应用于参数时,Mj 是可访问和适用的
  • 存在从 expr 到 Mj 第一个参数的类型的隐式标识、引用或装箱转换。

...

如果在任何封闭的命名空间声明或编译单元中都没有找到候选集,则会发生编译时错误。

因此,您必须将 DateTime 显式转换为 Nullable<DateTime> 或从头开始使用可空值:

DateTime now = DateTime.Now;
((DateTime?)now).Test();

DateTime? now = DateTime.Now;
now.Test();

【讨论】:

  • 那个链接说它隐式可转换的。如果不是,那么标准的静态方法调用也会失败。除非我误会你了。
  • @fearofawhackplanet:也许我表达得不好
  • 我仍然看不出您从规范中引用的哪些资格要求没有得到满足。该方法作为静态方法可见/适用,并且存在隐式转换。
  • 让我们重新讨论一下这个话题...关键点是,值类型 -> 可空转换是一种隐式转换,但它不是装箱转换。这就是列表中的第二个要点不适用的原因,即使它看起来应该适用。
【解决方案2】:

正如蒂姆所说的可以为空 +1

修复:

  public static class Extension
  {
    public static void Test(this DateTime? dt)
    {
    }
  }

  public class Program
  {
    private void Main()
    {
      DateTime? now = DateTime.Now;
      Extension.Test(now); 
      now.Test();  
   }
  }

【讨论】:

    【解决方案3】:

    var 不是类型。实际类型是在编译时计算出来的。如果将DateTime.Now 设置为var,它将识别为DateTime 类型,而不是Nullable<DateTime>,这就是它无法编译的原因。

    var 变量也称为Implicitly Typed Local Variables (C# Programming Guide)

    顺便说一句,您还可以为可空类型创建通用扩展方法:

    public static T? GenericMethod<T>(this T? source) where T : struct
    {
        //Do something
    }
    

    你可以调用任何可以为空的东西,声明它的类型:

    DateTime? dateTimeNullable = DateTime.Now;
    dateTimeNullable.GenericMethod();
    
    int? intNullable = 0;
    intNullable.GenericMethod();
    

    【讨论】:

      【解决方案4】:

      因为您为DateTime? 而不是DateTime 编写了扩展。

              DateTime? now = DateTime.Now;
              Extension.Test(now); // ok
              now.Test(); // no compile time error
      

              var now = new DateTime?(DateTime.Now);
              Extension.Test(now); // ok
              now.Test(); // no compile time error
      

      会起作用的。

      【讨论】:

        【解决方案5】:

        您现在需要使用可为空的正确类型创建变量,如下所示:

         DateTime? dateTime = DateTime.Now;
         dateTime.Test();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-23
          • 2014-06-11
          • 2021-03-22
          相关资源
          最近更新 更多