web-dev-qa-db-ja.com

インターフェイスのオプションのパラメーター

C#4.0の使用-インターフェイスとインターフェイスを実装するクラスの構築。インターフェイスでオプションのパラメーターを宣言し、クラスに反映させたい。だから、私は次のものを持っています:

 public interface IFoo
 {
      void Bar(int i, int j=0);
 }

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

これはコンパイルされますが、正しく見えません。それ以外の場合、インターフェイスメソッドのシグネチャに正しく反映されないため、インターフェイスにはオプションのパラメーターが必要です。

オプションのパラメーターをスキップして、null許容型を使用する必要がありますか?または、これは意図したとおりに機能し、副作用や結果はありませんか?

66
bryanjonker

Pre-optional-parametersの代替案を検討できます。

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

新しい言語機能の外観が気に入らない場合は、使用する必要はありません。

28
pdr

本当に奇妙なのは、インターフェイスのオプションパラメータに設定した値が実際に違いを生むことです。値がインターフェイスの詳細なのか、実装の詳細なのかを疑問視する必要があると思います。私は後者を言ったでしょうが、物事は前者のように振る舞います。たとえば、次のコードは1 0 2 5 3 7を出力します。

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

興味深いのは、インターフェースがパラメーターをオプションにした場合、それを実装するクラスが同じことをする必要がないことです。

// 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をどのように使用できますか?

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

エリック・リッパートは、この正確なトピックに関する興味深いシリーズを書きました: オプションの引数コーナーケース

58
Martin Brown

実装でパラメーターをオプションにする必要はありません。あなたのコードはそれからいくらか意味があります:

 public interface IFoo
 {
      void Bar(int i, int j = 0);
 }

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

このようにして、デフォルト値が明確になります。実際、インターフェイスがデフォルトを提供するため、実装のデフォルト値は効果がないと確信しています。

4
Tor Haugen

このようなものはどうですか?

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 */ }
}
3
Dave

考慮すべきことは、インターフェイスのリフレクションに基づいて機能するモックフレームワークを使用した場合に何が起こるかです。オプションのパラメーターがインターフェースで定義されている場合、インターフェースで宣言されているものに基づいてデフォルト値が渡されます。 1つの問題は、定義に異なるオプション値を設定することを妨げるものは何もないということです。

2
Hitesh

それはさておき、それはあなたが達成したいと思うように聞こえるものを正確に行います。

1
MojoFilter