5

Visual Studio 10(および現在は11)で奇妙なエラーが発生します。拡張メソッドがあります

public static S Foo<S, T>(this S s) where S : IEnumerable<T>
{
    return s;
}

今私が電話すると

"".Foo(); // => 'string' does not contain a definition for 'Foo' and no extension method 'Foo' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

私はボンネットの下で何が起こっているのか全く理解していません。厄介な部分は、インテリセンスがsをリストFooするIEnumberable<T>ことです。せいぜい、それはを与えるべきでしたtype can't be inferred error

私がそれをこのように呼ぶならば:

Extension.Foo(""); // => The type arguments for method 'Extension.Foo<S,T>(S)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

上記の場合、なぜ型推論できないのですか?

もっと:

私が持っているとしましょう:

public static S Foo<S, T>(this S s, T t) where S : IEnumerable<T>
{
    return s;
}

そして私が呼ぶなら:

"".Foo(1);

型推論はここではとても賢いので、戻っFooくるはずであり、それだけではありません!!IEnumerable<int>string

それで、コンパイラーがFoo最初の引数としてcharを期待していることを知ることができるなら、なぜ私の最初の例は単にコンパイルされないのですか?言い換えれば、最初の例でコンパイラがTその場合にcharであることを知っているのはなぜですか?

予想通り、これは2番目の例で機能します。

"".Foo('l');

結局のところ、文字列が。であるのに、なぜ最初の例のTように推測できないのか疑問に思っています。charIEnumberable<char>


編集:

SLaksから答えを得ました。しかし、コンパイラがオブジェクトを操作するために使用可能なメソッドを公開するときにジェネリック制約も考慮に入れることを考慮して、C#がこれ(型推論の一種)を行わないのは非常に奇妙です。

言い換えると:

public static S Foo<S, T>(this S s)
{
    return s;
}

すべてのでFoo利用可能になりますobject

public static S Foo<S, T>(this S s) where S : IEnumerable<T>
{
    return s;
}

がであることがわかっているため、Fooすべてので使用可能になります。だから私はC#がタイプを推測することさえできるだろうと思っていました!みんな、ありがとう!;)IEnumerable<T> SIEnumerable<T>T

4

1 に答える 1

9

型推論エンジンはそれを行うのに十分賢いわけではありません。

C#型推論は、メソッドシグネチャのみを調べます。
ジェネリック制約は署名の一部ではありません

Tは署名で直接使用されないため、コンパイラはそれを推測しません。

于 2012-11-13T14:16:54.490 に答える