...そしてフライドポテト。
Windows と MonoTouch の両方用にコンパイルしているコードベースがあります。朝の未明に、MonoTouch ではコンパイルされるが Windows では失敗する、この不自然な例のようなものをコーディングしました。
void Run()
{
// okay on both
exec("hello", 1);
// okay on MonoTouch
// compiler error on windows
exec("hello");
}
interface IFace { void foo(); }
void exec(string s, int n=0)
{
Console.Write("A");
}
void exec<T>(T t) where T:IFace
{
Console.Write("B");
}
MonoTouch では、これをコンパイルして実行し、次のように出力します。
AA
Windows では、この例ではコンパイル時エラーが発生します。
The type 'string' cannot be used as type parameter 'T' in the generic type or method 'App.Program.exec<T>(T)'. There is no implicit reference conversion from 'string' to 'App.Program.IFace'.
7.4.2 オーバーロード解決に関する C# 仕様では、7.4.2.1 適用可能な関数メンバーは同じ数の引数を持たなければならないと述べています。
A の引数の数は、関数メンバー宣言のパラメーターの数と同じです。7.4.2.1
したがって、MonoTouch コンパイラは、適用可能な関数メンバーを検索するときに既定の引数を考慮しているように見えますが、Windows コンパイラはそうではありません。したがって、関数メンバーの候補は次のとおりです。
// exec with no default parameters. not applicable because no int supplied
void exec(string,int);
// exec with default value for the second parameter.
// only considered on MonoTouch.
void exec(string,int=0);
// generic exec with string as the type, which is invalid
// due to the IFace constraint. Invalid on both platforms.
void exec<string>(string) : where T:IFace;
では、これは MonoTouch での該当する関数メンバー検索のバグですか、それとも Windows コンパイラは、既定でパラメーター化された非ジェネリック メソッドを有効と見なす必要がありますか?
乾杯、cm
EDITの回答の
後dlev
、制約付きと制約なしの両方のジェネリック メソッドをテストしましたが、Mono コンパイラは制約なしの場合に正しいメソッドを選択するようです。制約された場合、Mono コンパイラは制約を検討しているか、制約が失敗したときに代替案を見つけるためにバックトラックしているように見えます。
問題/バグは次のようになります。
void Run()
{
foo(1);
bar(1);
}
void foo(int a, int b = 0) { print("A"); }
void foo<T>(T t) { print("B"); }
void bar(int a, int b=0) { print("X"); }
void bar<T>(T t) where T : IFace { print("Y"); }
Windows と MonoTouch の両方で、foo
正しく印刷されB
ます。しかしbar
、Windows ではコンパイルに失敗しますがX
、MonoTouch では印刷されます。
EDIT2
興味のある人にとって、私の解決策は、デフォルトのパラメーターを削除し、明示的な呼び出しを要求することでした。私の実際のシステムでは、型制約によって 2 つのインターフェイスが指定されているため、 へのジェネリック呼び出しを簡単に変更することはできませんexec(IFace t) { ... }
。リファクタリングできると思いますが、これは私のシステムの要であり、現在のコンパイルの問題は次のように解決されます。
void exec(string a) { exec(a,0); }
void exec(string a, int b) { ... }
void exec<T>(T t) where T : IFace, IFace2 { ... }
ダブルチアーズ、cm