1

以下のコードでは、 という名前の 2 つのオーバーロードされたメソッドを定義していますBar。ではFoo()、 を 3 回呼び出しましBarたが、3 回目の呼び出しでエラーが発生しました。

最初の 2 つは、予想されるオーバーロードに解決されます。ただし、3番目は次のエラーを生成しました:

The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Bar<T>(T, string, params object[])'. There is no implicit reference conversion from 'string' to 'System.Exception'.

明らかに 3 番目の呼び出しは "Bar()" にバインドされていますが、最初のパラメーターを例外に変換していません。また、2 番目の引数が文字列であることは、コンパイラをスローしていることも明らかです。文字列でない場合 (ケース 2)、解像度は問題ありません。しかし、失敗した行は "Bar()" にバインドする必要があることは明らかです (最初のパラメーターは明確に文字列であるため)。

コンパイラがこのバインディングを使用している理由を誰か説明できますか? 私は創造的な回避策を検討しますが、私が本当に探しているのは、なぜこれが起こっているのかの説明です. 私は C# 言語仕様に時間を費やしましたが、明確な答えを見つけることができませんでした (つまり、諦めました)。明らかに、Barメソッドの名前を変更したり、名前付き引数を指定したり、パラメーターの 1 つをマークしたりできますref...しかし、これらのいずれも私の特定のシナリオには理想的ではありません。

関連性があるというわけではありませんが、まさにこれを行う Java コードを作成しましたが、コンパイラーには問題がありませんでした。

コード:

public void Bar(string s, params object[] ps) { } // Call this "Bar()"
public void Bar<E>(E e, string s, params object[] ps) where E : Exception { } // Call this "Bar<T>()"

public void Foo()
{
    Exception e;
    Object o1, o2;

    Bar(e, "fmt {0}", o); // Resolves fine, as expected
    Bar("fmt {0} {2}", o1, o2); // Also resolves as expected
    Bar("fmt {0} {2}", "bar", o1); // Error!
}
4

2 に答える 2

4

答えは、オーバーロード マッチングは制約を考慮しないということです。これが C# の仕様であるかどうかについては、完全にはわかりません。マッチングは常に最も具体的なオプションを使用し、string as genericTは常に string as よりも具体的ですObject(子の型ではなく実際の型に一致するため)。Eric Lippert のブログのConstraints are not part of the signatureを参照してください。

これを機能させるには、例外の制約が必要な場合は、void Bar(Exception E, ...)可能であれば使用してください。

于 2012-05-16T23:19:20.390 に答える
2

Bar("fmt {0} {2}", "bar", o1);// エラー!特異性の優先度により、2 番目のパラメーターが文字列 (オブジェクトよりも文字列の方が具体的) であるメソッド シグネチャを検索し、Type 引数を解決しようとしますが、解決できませんでした。それを説明するために、3 番目の呼び出しを次のように置き換えてみてください。

Bar("fmt {0} {2}", (object)"bar", o1); // Now it is fine for compiler!
于 2012-05-16T23:16:09.303 に答える