21
class Class1<T>
{
    public virtual void Update(T entity)
    {
        Update(new List<T>() { entity }); //It's failed
    }

    public virtual void Update(IEnumerable<T> entities)
    {
    }

    public virtual void Update<TSub>(TSub entity) where TSub : T
    {
    }

    public virtual void Update<TSub>(IEnumerable<TSub> entities) where TSub : T
    {
    }
}

私はコードを持っています。しかし、それは常に失敗しました。

Update(new List<T>() { entity })に置き換えればUpdate((new List<T>() { entity }).AsEnumerable())OKです。

3番目のメソッドを削除してもOKですUpdate<TSub>(TSub entity) where TSub : T

理由を教えてもらえますか?

4

3 に答える 3

20

わかりました、これを注意深く見ていきましょう。我々は持っています

Update(new List<T>()); 

そして 3 つの候補 - これらの候補の署名のみを気にすることに注意してください。そのため、署名の一部ではない戻り値の型と制約を取り除きます。

Update(IEnumerable<T> entities)
Update<U>(U entity) 
Update<V>(IEnumerable<V> entities) 

最初のタスクは、最後の 2 つの候補について型推論を行うことです。推論が失敗した場合、それらは適用可能な候補ではありません。

2番目の方法を検討してください

Update<U>(U entity) 

type の引数List<T>と仮パラメータがありますU。したがって、 であると推測されUますList<T>

3 番目の方法を検討してください。

Update<V>(IEnumerable<V> entities)

type の引数と typeList<T>の仮パラメーターがありますIEnumerable<V>List<T>を実装IEnumerable<T>しているので、V は T であると推測します。

よし、候補リストは次のようになった:

Update(IEnumerable<T> entities)
Update<List<T>>(List<T> entity) 
Update<T>(IEnumerable<T> entities) 

これらの候補はすべて該当しますか? はい。いずれの場合List<T>も、仮パラメータ型に変換できます。それらのいずれもまだ排除することはできません。

適用可能な候補のみが得られたので、どれが一意に最適かを判断する必要があります。

3 つ目はすぐに削除できます。3 番目のものと最初のものは、仮パラメータ リストが同じです。C# の規則では、仮パラメーター リストが同一である 2 つのメソッドがあり、そのうちの 1 つが「自然に」そこに到達し、1 つが型置換によってそこに到達した場合、置換された方が失われます。

最初のものを削除することもできます。明らかに、2 番目の完全一致は、最初の不正確一致よりも優れています。

これにより、2 人目が最後の男として残ります。過負荷解決の戦いに勝ちます。その後、最終的な検証中に、制約に違反していることを発見しました:List<T>の派生クラスであることが保証されていませんT

したがって、オーバーロードの解決は失敗します。あなたの議論により、選択された最良の方法が無効になりました。

電話すればUpdate((new List<T>() { entity }).AsEnumerable())大丈夫です。

正しい。もう一度やり直してください。3 つの候補:

Update(IEnumerable<T> entities)
Update<U>(U entity) 
Update<V>(IEnumerable<V> entities) 

type の引数があるIEnumerable<T>ので、2 番目と 3 番目は次のように推測します。

Update(IEnumerable<T> entities)
Update<IEnumerable<T>>(IEnumerable<T> entity) 
Update<T>(IEnumerable<T> entities) 

これで、同一のパラメータ リストを持つ 3 つの適用可能な候補ができました。建設中にそこに到達したものは、自然のものよりも自動的に悪いので、2番目と3番目を削除して、最初のものだけを残します. それは勝ち、違反すべき制約はありません。

3番目の方法を削除しても大丈夫です

あなたの発言は誤りです。これにより、最初のシナリオと同じエラーが発生します。3 番目の候補者を奪っても、1 番目の候補者が突然 2 番目の候補者を打ち負かすことはありません。

于 2013-03-22T16:35:45.233 に答える
12

制約は署名の一部ではありません。Eric Lippert がこのトピックに関するすばらしい記事を書いています。

于 2013-03-22T11:14:01.993 に答える
2

あなたは本質的に、なぜコンパイラがからList<T>への暗黙のキャストを作成しないのかを尋ねていIEnumerable<T>ます。その理由は、C# チームが、潜在的なあいまいさのケースはコンパイラではなくプログラマが解決しなければならないという意図的な設計上の決定を下したためです。(VB.NET チームは別の決定を下したことに注意してください。認識されたプログラマーの意図と一致する賢明なことを常に試みます。)

このような場合の利点は、驚きが最小限に抑えられることです。欠点は、より冗長なコードが必要になる場合があることです。

于 2013-03-22T11:10:16.693 に答える