关于c#:可选参数和接口 – 意外结果

Optional Parameters and Interfaces - Unexpected result

本问题已经有最佳答案,请猛点这里访问。

我支持一些具有可选参数和接口的代码。

作为一个简单的例子:我在接口中有一个默认值2,在实现类中有一个默认值1。

1
2
3
4
5
6
7
8
9
10
11
12
public interface IOptionalInterface
{
    int Get(int x = 2);
}

public class ClassX : IOptionalInterface
{
    public int Get(int x = 1)
    {
        return x;
    }
}

如我所料,这段代码通过了。

1
        Assert.AreEqual(new ClassX().Get(), 1);

但是,当我将类作为接口传递回并稍后调用它时,我从接口中得到了可选参数;这让我吃惊。

1
2
3
4
5
6
7
8
9
10
    private IOptionalInterface Build()
    {
        return new ClassX();
    }

    public void Expect1()
    {
        var y = Build();
        Assert.AreEqual(y.Get(), 1);  // fails, it returns 2.
    }

我遗漏的主要设计考虑因素是什么,使得这个优先考虑?

有没有一种干净的方法来确保实现类设置默认值?


可选参数是在调用站点调用的纯编译时功能。

当使用可选参数调用方法时,编译器会查找该参数的默认值,并在调用中插入该文字值。因此,默认值是根据调用站点的编译时类型来解析的。


这是因为像扩展方法一样,可选参数是编译器的把戏,而不是真正的语言特性。

因此,适当地-使用扩展方法解决问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface IDoSomething {
    void DoThis(int parameter);
}

public static class DoSomethingDefaults {
    public static void DoThis(this IDoSomething x) {
        x.DoSomething(123); //default value
    }
}

///
new ClassThatImplementsDoSomething().DoThis();
new ClassThatImplementsDoSomething().DoThis(456);

它不像真正的可选参数那样圆滑,但在大多数情况下,它们都会做同样的事情并正确工作。

将默认值与接口放在一起(我甚至推荐相同的文件),希望对于项目的新成员来说,跟踪正在发生的事情不会太困难。