【问题标题】:Optional arguments in interface without any default value接口中的可选参数,没有任何默认值
【发布时间】:2015-12-23 16:41:30
【问题描述】:

我很惊讶 C# 使用接口的可选方法参数的值,而不是来自实现此接口的类。例如:

using System;
                
public class Program
{
    private static IMyInterface instance;
    
    public static void Main()
    {
        instance = new MyClass();
        
        instance.PrintOpt();
        ((MyClass)instance).PrintOpt();
    }
}

public interface IMyInterface
{
    void PrintOpt(bool opt = false);
}

public class MyClass : IMyInterface
{
    public void PrintOpt(bool opt = true) 
    {
        Console.WriteLine($"Value of optional argument is {opt}");
    }
}

产生输出:

可选参数的值为 False

可选参数的值为真

我的问题是:是否可以在没有默认值或“可覆盖”的接口中定义可选参数,因此对保存在接口类型变量中的实例的方法调用使用在实现此接口的类中定义的可选值?

【问题讨论】:

  • 为何如此令人惊讶?您将实例变量键入为 IMyInterface - 为什么您希望它使用接口定义以外的任何内容?
  • 来自 Eric Lippert 的 this SO answer 中很好的相关解释
  • 我很惊讶默认值不是方法签名的一部分。换句话说......由于接口指定了一个默认为 FALSE 的 bool 参数的方法,我很惊讶该类不需要实现默认为 FALSE 的 bool 参数的方法。

标签: c# optional-parameters


【解决方案1】:

如果您了解内部如何处理可选参数,这并不奇怪:它们在编译期间内联。

换句话说,在调用方法的地方,编译器会传递任何可选参数 - 如果您正在调用接口方法,编译器不知道有一个实现与 不同 可选参数。使用这样的代码可以最清楚地看到差异:

IMyInterface interface = new MyClass();
MyClass theClass = (MyClass)interface;

interface.PrintOpt(); // false
theClass.PrintOpt(); // true

编译成这个(翻译回C#):

interface.PrintOpt(false);
theClass.PrintOpt(true);

IL 代码中的“默认”参数不再是“默认”——它们只是另一个显式传递的参数。

如果您想使用可覆盖的可选参数,只需使用方法重载即可。或者更好的是,使用没有任何意义的默认值(例如nulldefault(int?)),并对方法内部的默认值进行任何替换。这与首先​​在 C# 中包含可选参数的最初原因是一致的——VB 风格的 COM 接口通常具有带有几十个参数的方法,几乎​​所有这些参数都是可选的。到目前为止,当你想调用这样的方法时,你必须做类似的事情

comInterface.MyMethod(TheActualArgumentICareAbout, Type.Missing, Type.Missing, 
                      Type.Missing, Type.Missing, ...);

现在你可以做

comInterface.MyMethod(argument, anotherSuperUseful: true);

这种区别很重要——这也意味着您永远不应该更改任何公共方法的默认参数。任何使用您的库而不重新编译的人仍将使用旧的默认值。它类似于const 值或枚举的处理方式。如果您使用 null 作为默认值,则实际的默认值将在方法本身内部,并且所有调用者将“看到”正确的默认值,即使他们不重新编译(类似于使用 public static readonly 字段代替const 或具有属性而不是枚举的类)。

【讨论】:

  • 实际上,我会说可选参数不存在,只有具有默认值的参数。
猜你喜欢
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
  • 2021-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-08
相关资源
最近更新 更多