あなたが持っている場合:
F(G<A,B>(4));
これは、ユーザーが、G と A、および B と定数 4 を比較した結果の 2 つのパラメーターを使用してメソッド F を呼び出したいということですか?
それとも、型パラメーター A と B および 4 の引数を使用してジェネリック メソッド G を呼び出した結果で F を呼び出すことを意味しますか?
ということで、念のため試してみました。これはうまく機能することがわかりました:
void F(int x) { }
int G<T, U>(int x) { return x; }
class A { }
class B { }
void Main()
{
F(G<A,B>(4));
}
しかし、これは多くのコンパイル エラーを生成します。
void F(bool x, bool y) { }
void Main()
{
int G = 0, A = 1, B = 2;
F(G<A,B>(4));
}
型または名前空間名 'A' が見つかりませんでした (F4 キーを押して、using ディレクティブまたはアセンブリ参照を追加してください)
型または名前空間名 'B' が見つかりませんでした (using ディレクティブまたはアセンブリ参照がありませんか?)
変数 'G' はジェネリック メソッドではありません。式リストを意図している場合は、< 式を括弧で囲みます。
したがって、答えは、式F(G<A,B>(4))
が一般的な関数呼び出しとして解釈されるということです。F(G<A,B>4)
コンパイラにこれを 2 つのパラメータF((G)<A,B>(4))
の1 つの関数呼び出しとして強制的に処理させる方法はいくつもありますF(G>A,B>(4))
。
C# 仕様の 7.6.4.2 を読む必要があります。これは、文法のあいまいさを扱い、この例をほぼ逐語的に説明しています。引用するには:
トークンのシーケンスが単純名 (§7.6.2)、メンバー アクセス (§7.6.4)、または型で終わるポインター メンバー アクセス (§18.5.2) として (コンテキストで) 解析できる場合-argument-list (§4.4.1)、終了トークンの直後の
>
トークンが調べられます。それがの1つである場合( ) ] } : ; 、 。? == != | ^
次に、type-argument-list は simple-name、member-access、または pointer-member-access の一部として保持され、トークンのシーケンスのその他の可能な解析は破棄されます。
ここで、G
は単純名であり、問題は<A,B>
、 がこの単純名の一部として型引数リストとして解釈されるかどうかです。
の(
後に が>
あるので、フラグメントG<A,B>
はメソッドの単純名です。このメソッドは、型引数A
とB
4 の引数を持つジェネリック メソッドです。F
したがって、単一のパラメーターを持つメソッドです。
注目すべき興味深い点の 1 つは、これは、解析が失敗した場合にコンパイラが代替手段を考慮しないケースであるということです。pswgの回答からわかるように、唯一の有効な解釈がF
2つのパラメーターを取るメソッドである場合でも、それは考慮されません。