12

.NET 4 を使用して、以下のサンプルの最初のメソッド呼び出しをコンパイラが解決できないことに混乱しています。

using System;

namespace MethodResolutionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            NonGeneric foo = null;

            // ambiguous
            foo.Ext1(x => new NonGeneric());

            // resolves to first Ext1
            foo.Ext1(x => new NonGeneric(), 1);


            // resolves to first Ext2
            foo.Ext2(x => new NonGeneric());

            // resolves to first Ext2
            foo.Ext2(x => new NonGeneric(), 1);

            // resolves to second Ext2
            foo.Ext2(x => "foo");

            // resolves to second Ext2
            foo.Ext2(x => "foo", 1);


            // resolves to first Ext3
            foo.Ext3(x => new NonGeneric());

            // resolves to first Ext3
            foo.Ext3(x => new NonGeneric(), 1);

            // resolves to second Ext3
            foo.Ext3(x => "foo");

            // resolves to second Ext3
            foo.Ext3(x => "foo", 1);
        }
    }

    public class NonGeneric
    {
    }

    public class Generic<T> : NonGeneric
    {
    }

    public static class Extensions1
    {
        public static NonGeneric Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0)
        {
            return null;
        }

        public static Generic<TNext> Ext1<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0, string s = null)
        {
            return null;
        }
    }

    // only difference between Extensions2 and Extensions1 is that the second overload no longer has a default string parameter
    public static class Extensions2
    {
        public static NonGeneric Ext2(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0)
        {
            return null;
        }

        public static Generic<TNext> Ext2<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0)
        {
            return null;
        }
    }

    // Extensions3 explicitly defines an overload that does not default the int parameter
    public static class Extensions3
    {
        public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext)
        {
            return Ext3(first, getNext, default(int));
        }

        public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0)
        {
            return null;
        }

        public static Generic<TNext> Ext3<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0)
        {
            return null;
        }
    }
}

誰でもこれに光を当てることができますか?(上記のように) コンパイラを支援するために API を変更する以外に、ここで前進する方法はないと思いますExtensions3が、より簡単でより良い方法がある場合は、それを聞いてみたいです.

4

1 に答える 1

1

Ext12 番目の拡張メソッドには 2 つの省略可能なパラメーターがあるため、あいまいです。最初の呼び出しでは両方のパラメーターが省略されているため、コンパイラーはどちらを使用するかを認識できません。

C# 4.0 言語仕様から:

§7.5.3 過負荷の解決:

適用可能な候補関数メンバーのセットが与えられると、そのセット内の最適な関数メンバーが特定されます。セットに関数メンバーが 1 つしか含まれていない場合、その関数メンバーが最適な関数メンバーです。それ以外の場合、§7.5.3.2 の規則を使用して各関数メンバーが他のすべての関数メンバーと比較される場合、最良の関数メンバーは、指定された引数リストに関して他のすべての関数メンバーよりも優れている 1 つの関数メンバーです。他のすべての関数メンバーよりも優れた関数メンバーが 1 つだけ存在しない場合、関数メンバーの呼び出しはあいまいであり、バインド時エラーが発生します。

さらに、§7.5.3.2 Better function memberの下で:

対応する引数のないオプションのパラメーターは、パラメーター リストから削除されます。

これが意味することは、メソッド呼び出しで最後の 2 つの引数を省略し、NonGeneric型が推論されると (§7.5.2 の型推論について読んでください)、両方のメソッドが次のようになるということです。

Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext)

したがって、それらはあいまいになります...

詳細については、仕様の §7.5.3.2 または §7.5.3 全体を読むことをお勧めします。

解決策は、メソッド宣言を変更するか、最初のオーバーロードを完全に削除して、2 番目のオーバーロードに任せることです:)

于 2012-11-13T11:08:17.407 に答える