关于c#:接口的可选参数

Optional parameters for interfaces

使用C 4.0——构建接口和实现接口的类。我想在接口中声明一个可选参数,并让它反映在类中。所以,我有以下几点:

1
2
3
4
5
6
7
8
9
 public interface IFoo
 {
      void Bar(int i, int j=0);
 }

 public class Foo
 {
      void Bar(int i, int j=0) { // do stuff }
 }

这是编译的,但看起来不太对劲。接口需要有可选参数,否则它在接口方法签名中不能正确反映。

我应该跳过可选参数并只使用可为空的类型吗?或者这是否会按预期工作而没有副作用或后果?


真正奇怪的是,您为接口中的可选参数输入的值实际上会产生差异。我想您必须质疑这个值是接口细节还是实现细节。我本来会说后者的,但事情的表现却和前者相似。例如,以下代码输出1 0 2 5 3 7。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Output:
// 1 0
// 2 5
// 3 7
namespace ScrapCSConsole
{
    using System;

    interface IMyTest
    {
        void MyTestMethod(int notOptional, int optional = 5);
    }

    interface IMyOtherTest
    {
        void MyTestMethod(int notOptional, int optional = 7);
    }

    class MyTest : IMyTest, IMyOtherTest
    {
        public void MyTestMethod(int notOptional, int optional = 0)
        {
            Console.WriteLine(string.Format("{0} {1}", notOptional, optional));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyTest myTest1 = new MyTest();
            myTest1.MyTestMethod(1);

            IMyTest myTest2 = myTest1;
            myTest2.MyTestMethod(2);

            IMyOtherTest myTest3 = myTest1;
            myTest3.MyTestMethod(3);
        }
    }
}

有趣的是,如果您的接口使参数成为可选的,那么实现它的类就不必这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Optput:
// 2 5
namespace ScrapCSConsole
{
    using System;

    interface IMyTest
    {
        void MyTestMethod(int notOptional, int optional = 5);
    }

    class MyTest : IMyTest
    {
        public void MyTestMethod(int notOptional, int optional)
        {
            Console.WriteLine(string.Format("{0} {1}", notOptional, optional));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyTest myTest1 = new MyTest();
            // The following line won't compile as it does not pass a required
            // parameter.
            //myTest1.MyTestMethod(1);

            IMyTest myTest2 = myTest1;
            myTest2.MyTestMethod(2);
        }
    }
}

然而,似乎是错误的是,如果显式实现接口,那么在类中为可选值提供的值是无意义的。在下面的示例中,如何使用值9?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Optput:
// 2 5
namespace ScrapCSConsole
{
    using System;

    interface IMyTest
    {
        void MyTestMethod(int notOptional, int optional = 5);
    }

    class MyTest : IMyTest
    {
        void IMyTest.MyTestMethod(int notOptional, int optional = 9)
        {
            Console.WriteLine(string.Format("{0} {1}", notOptional, optional));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyTest myTest1 = new MyTest();
            // The following line won't compile as MyTest method is not available
            // without first casting to IMyTest
            //myTest1.MyTestMethod(1);

            IMyTest myTest2 = new MyTest();            
            myTest2.MyTestMethod(2);
        }
    }
}

埃里克·利珀特就这个确切的主题写了一个有趣的系列文章:可选的论据角案例


您可以考虑预先可选的参数替代:

1
2
3
4
5
6
7
8
9
10
11
12
public interface IFoo
{
    void Bar(int i, int j);
}

public static class FooOptionalExtensions
{
    public static void Bar(this IFoo foo, int i)
    {
        foo.Bar(i, 0);
    }
}

如果您不喜欢新语言功能的外观,则不必使用它。


您不必在实现中使参数成为可选的。您的代码将更加合理:

1
2
3
4
5
6
7
8
9
 public interface IFoo
 {
      void Bar(int i, int j = 0);
 }

 public class Foo
 {
      void Bar(int i, int j) { // do stuff }
 }

这样,默认值就明确了。实际上,我很确定实现中的默认值不会有任何影响,因为接口为它提供了一个默认值。


像这样的东西怎么样?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface IFoo
{
    void Bar(int i, int j);
}

public static class IFooExtensions
{
    public static void Baz(this IFoo foo, int i, int j = 0)
    {
        foo.Bar(i, j);
    }
}

public class Foo
{
    void Bar(int i, int j) { /* do stuff */ }
}


要考虑的是当使用模拟框架时会发生什么,这些框架基于接口的反射工作。如果在接口上定义了可选参数,则将根据接口中声明的内容传递默认值。一个问题是,没有什么能阻止您在定义上设置不同的可选值。


撇开不谈,这将完全达到你想要达到的目标。