web-dev-qa-db-ja.com

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

インターフェイスでパラメーターをオプションとして指定する場合、C#4のオプションパラメーターを使用すると、実装クラスでそのパラメーターをオプションにする必要はありません。

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フレームワークを使用して具体的なクラスを挿入する場合インスタンス)実際には、呼び出し側は常にデフォルト値を提供する必要があるため、デフォルト値を使用しても意味がありません。

343
theburningmonk

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

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

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


// 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の新しいバージョンを送ってほしいと頼む必要がありますか?

それは飛ぶつもりはありません。 two人々がBの作者を呼び出し、そのうちの1人がデフォルトをtrueにしたいのに、1人がそれをfalseにしたい場合はどうでしょうか? Bの作成者が単に一緒に遊ぶことを拒否した場合はどうなりますか?

おそらくその場合、彼らは言う必要があります:

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

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

225
Eric Lippert

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

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

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

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

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

46
CodesInChaos

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

26
Olhovsky

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

5
Ariel Arjona