1

...そしてフライドポテト。

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

4

1 に答える 1

1

仕様のセクション 7.5.3.2 からのこの行は、これが Mono コンパイラのバグであることを示唆しています。

それ以外の場合、MP のすべてのパラメーターに対応する引数があり、MQ の少なくとも 1 つのオプションのパラメーターをデフォルトの引数で置き換える必要がある場合、MP は MQ よりも優れています。

つまり、適用可能なメソッド呼び出しを有効にするためにオプションのパラメーターの値を置き換える必要がある場合、そのメソッドは、そのような置換を必要としないメソッドよりも一致度が低いと見なされます。

また、MS C# コンパイラはバックトラックしません。メソッドがオーバーロード解決規則に従って最適であると判断されると、その仮定の下でコンパイルが続行されます。後の分析で、選択したメソッドがエラーになると判断された場合 (たとえば、置換されたジェネリック引数が制約に違反しているため)、そのエラーについて通知されます。

はい、制約は署名の一部ではないため、オーバーロードの解決では制約は考慮されませんT

于 2012-07-09T23:28:17.767 に答える