インターフェースで定義されたC#4オプションパラメーターがクラスの実装に適用されないのはなぜですか?


361

あなたがインターフェイス上でオプションのパラメータを指定した場合、私はC#4でのオプションのパラメータを持つことに気づいtは、ドン任意の実装クラスでそのパラメータのオプションを行う必要があります。

public interface MyInterface
{
    void TestMethod(bool flag = false);
}

public class MyClass : MyInterface
{
    public void TestMethod(bool flag)
    {
        Console.WriteLine(flag);
    }
}

したがって:

var obj = new MyClass();        
obj.TestMethod(); // compiler error

var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false

オプションのパラメーターがこのように機能するように設計されている理由を誰かが知っていますか?

一方では、インターフェースで指定されたデフォルト値をオーバーライドする機能は便利だと思いますが、正直なところ、インターフェースでデフォルト値を指定できるかどうかは、実装の決定であるためわかりません。

一方、この切断は、具象クラスとインターフェースを常に交換して使用できるわけではないことを意味します。もちろん、これは実装でデフォルト値が指定されている場合は問題になりませんが、具体的なクラスをインターフェースとして公開している場合(たとえば、IOCフレームワークを使用して具体的なクラスを挿入する場合)、実際にはありません。呼び出し側は常にデフォルト値を提供する必要があるため、デフォルト値を持つポイント。


22
オプションなので?
2010

1
ただし、オブジェクトインスタンスをにキャストMyInterfaceして、オプションのパラメータで呼び出すことができます ((MyInterface)obj).TestMethod();
ジムミッシェル、2011

7
@oded-しかし、このパラメーターがコントラクトでオプションであると言う場合、なぜ実装者がそれをオプションにしないことを許可するのですか?それは、契約を利用しようとしている人を混乱させるだけではありませんか?
theburningmonk

1
この場合、パラメータは実装メソッドの呼び出しではなく実装ではオプションであると言えると思います。クラスでメソッドを呼び出すときは、クラスルールに従う必要があります(クラスではパラメータはオプションではないので、それなしでメソッドを呼び出さないでください)、そしてインターフェースを実装するときは、インターフェースのルールに従う必要があるので、オプションのパラメーターの有無にかかわらずメソッドをオーバーライドできます。ただの意見。
Mohamad Alhamoud、2011

回答:


236

更新:この質問は、2011年5月12日の私のブログの主題でした。素晴らしい質問をありがとう!

説明したとおりのインターフェースがあり、それを実装する100のクラスがあるとします。次に、インターフェースのメソッドの1つのパラメーターの1つをオプションにすることを決定します。あなたが正しいことはコンパイラが開発者にそのインターフェースメソッドのすべての実装を見つけさせ、パラメータもオプションにすることだと示唆していますか?

それをしたとしましょう。ここで、開発者が実装のソースコードを持っていなかったとします。


// in metadata:
public class B 
{ 
    public void TestMethod(bool b) {}
}

// in source code
interface MyInterface 
{ 
    void TestMethod(bool b = false); 
}
class D : B, MyInterface {}
// Legal because D's base class has a public method 
// that implements the interface method

Dの作者は、どのようにしてこの作業を行うことになっていますか?彼らはあなたの世界でBの作者を電話で呼び出し、メソッドにオプションのパラメーターを持たせる新しいバージョンのBを送ってくれるように依頼する必要がありますか?

それは飛ばないでしょう。どのような場合には2人がBの著者呼び出し、そのうちの一つは、デフォルトはtrueになりたがっているそのうちの一つは、それが虚偽であることを望んでいますか?Bの作者が単に一緒に遊ぶことを拒否した場合はどうなりますか?

おそらくその場合、彼らは言うことを要求されるでしょう:

class D : B, MyInterface 
{
    public new void TestMethod(bool b = false)
    {
        base.TestMethod(b);
    }
}

提案された機能は、プログラマーに多くの不便を加えているようであり、対応する代表的な能力が増加していません。ユーザーのコストの増加を正当化するこの機能の説得力のある利点は何ですか?


更新:以下のコメントで、supercatは言語に真の力を追加し、この質問で説明されているものと同様のいくつかのシナリオを可能にする言語機能を提案します。参考までに、その機能(インターフェースのメソッドのデフォルト実装)がC#8に追加されます。


9
@supercat:そうする予定はありませんが、そのような機能は可能です。以前に提案されました。C#4の設計プロセス中に、「すべてを拡張する」機能と呼ばれる機能の多くを検討しました。拡張メソッドがあるので、拡張イベント、拡張プロパティ、拡張コンストラクター、拡張インターフェイスなどがあるとはどういうことでしょうか。 。インターフェースに「アタッチ」して「これらのメソッドはこのインターフェースのデフォルトの実装である」と言うことができるクラスは、「拡張インターフェース」を特徴付ける1つの可能な方法です。面白いアイデア。
Eric Lippert、2012年

16
直感的ではないと思う理由を明確にするために:オプションのパラメーターは「メソッドの呼び出し元にとってオプション」であり、「インターフェースの実装者にとってオプション」ではありません。
Stefan de Kok、2012年

8
「彼らはあなたの世界でBの作者に電話で電話をかけ、彼らに新しいバージョンを送ってくれるように頼むことを要求されていますか[...]?」いいえ、電話は必要ありません。BはもはやMyInterfaceの豊富さと見なすことができないはずであり、Dの作成者はコンパイラによってそれを認識させることができます。Dの作成者は、デフォルトのパラメーターを受け入れるTestMethodを使用してDを実装する必要があります。これは、インターフェースの作成者が必要とするものであるためです-誰かがそれを壊したいと思うかもしれないので、インターフェースの作成者が制約を強制することを許可しないことに反対しています。それは良い議論ではありません。
philofinfinitejest 2013

7
@EricLippertオプションのパラメーターがコーディングの便宜のために指定されている場合、はい、実装に不便を強いることは直観に反します。しかし、オプションのパラメーターを使用して強力な機能であるメソッドのオーバーロードを最小限に抑えている場合、これらのオプションの値は非常に重要になる可能性があり、それらを無視すると確実にその能力が弱まります。具体的な実装がインターフェースとは異なるデフォルト値を指定する場合は言うまでもありません。許可するのは非常に奇妙な切断のようです。
philofinfinitejest 2013

8
ここの@philofinfinitejestに同意します。インターフェイスは何かができることを伝えます。インターフェイスの指定とは異なるデフォルト値を持つインターフェイスの実装が渡された場合、それをどのようにして知ることができますか?ねえ、私はデフォルトとしてtrueを渡すインターフェイスを持っているので、なぜこれがfalseになるのですか?それは、私が期待したインターフェイスを取得できなかったように思えます。さらに悪いことに、インターフェイスではなく実装に合わせてプログラミングする必要があります。
アーロンブロー2014年

47

オプションのパラメーターは、属性でタグ付けされるだけです。この属性は、呼び出しサイトでそのパラメーターのデフォルト値を挿入するようコンパイラーに指示します。

呼び出しobj2.TestMethod();は置き換えられますobj2.TestMethod(false);、JIT時ではなく、C#コードがILにコンパイルさときにます。

つまり、ある意味では、常に呼び出し側がオプションのパラメーターを使用してデフォルト値を提供します。これは、バイナリのバージョン管理にも影響します。デフォルト値を変更しても、呼び出しコードを再コンパイルしない場合は、古いデフォルト値が引き続き使用されます。

一方、この切断は、具象クラスとインターフェースを常に交換して使用できるわけではないことを意味します。

インターフェイスメソッドが明示的実装されている場合は、すでにそれを行うことはできません。


1
実装者に明示的に実装することを強制できますか?
クラッシュ

30

デフォルトのパラメーターはランタイムではなくコンパイル時に解決されるためです。したがって、デフォルト値は、呼び出されるオブジェクトに属しているのではなく、呼び出されている参照タイプに属しています。


7

オプションのパラメーターは、私が理解しているものからのマクロ置換のようなものです。それらはメソッドの観点からは本当にオプションではありません。その成果物は、インターフェースにキャストした場合に異なる結果が得られる動作です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.