使用默认参数和泛型的方法解决问题

Ken*_*art 12 .net c# generics overload-resolution default-parameters

使用.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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以对此有所了解吗?我怀疑除了修改我的API以帮助编译器之外我没有其他方法(Extensions3如上所述),但如果有更简单/更好的方式,那么我很乐意听到它.

khe*_*ang 1

它是不明确的,因为第二个扩展方法中有两个可选参数Ext1。因为在第一次调用中两个参数都被省略,所以编译器不知道您要使用哪个。

\n\n

来自C# 4.0 语言规范

\n\n

\xc2\xa77.5.3 重载解析

\n\n
\n

给定一组适用的候选函数成员,即可找到该组中的最佳函数成员。如果该集合仅包含一个函数成员,则该函数成员是最佳函数成员。否则,最好的函数成员是相对于给定参数列表优于所有其他函数成员的一个函数成员,前提是使用 \xc2\xa77.5.3 中的规则将每个函数成员与所有其他函数成员进行比较。 2. 如果不存在一个优于所有其他函数成员的函数成员,则该函数成员调用将不明确,并且会发生绑定时错误。

\n
\n\n

此外,在\xc2\xa77.5.3.2 Better function member下:

\n\n
\n

没有对应参数的可选参数将从参数列表中删除

\n
\n\n

这意味着,当您省略方法调用中的最后两个参数并NonGeneric推断类型时(请阅读 \xc2\xa77.5.2 下的类型推断),两种方法将如下所示:

\n\n
Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这样一来,他们就变得暧昧了……

\n\n

我建议阅读 \xc2\xa77.5.3.2 甚至整个 \xc2\xa77.5.3 规范以获取更多信息。

\n\n

解决方案是更改方法声明或完全删除第一个重载并让第二个重载完成工作:)

\n