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

时间:2021-01-30 11:10:51

Using .NET 4, I am confused by the inability of the compiler to resolve the first method call in the sample below.

使用.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;
        }
    }
}

Can anyone shed some light on this? I suspect I don't really have a way forward here other than modifying my APIs to help the compiler (as per Extensions3 above), but if there is an easier/better way then I'd love to hear it.

任何人都可以对此有所了解吗?我怀疑除了修改我的API以帮助编译器之外我没有真正的前进方向(根据上面的Extensions3),但如果有更简单/更好的方式,那么我很乐意听到它。

1 个解决方案

#1


1  

It is ambiguous because you have two optional parameters in the second Ext1 extension method. Because both parameters are omitted in the first call, the compiler doesn't know which one you want to use.

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

From C# 4.0 Language Specification:

来自C#4.0语言规范:

§7.5.3 Overload resolution:

§7.5.3过载分辨率:

Given the set of applicable candidate function members, the best function member in that set is located. If the set contains only one function member, then that function member is the best function member. Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in §7.5.3.2. If there is not exactly one function member that is better than all other function members, then the function member invocation is ambiguous and a binding-time error occurs.

给定一组适用的候选函数成员,找到该集合中的最佳函数成员。如果集合只包含一个函数成员,那么该函数成员是最好的函数成员。否则,最佳函数成员是一个函数成员,它比给定参数列表中的所有其他函数成员更好,前提是使用§7.5.3.2中的规则将每个函数成员与所有其他函数成员进行比较。如果没有一个函数成员优于所有其他函数成员,则函数成员调用不明确并且发生绑定时错误。

Further, under §7.5.3.2 Better function member:

此外,根据§7.5.3.2更好的功能成员:

Optional parameters with no corresponding arguments are removed from the parameter list

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

What this means is that when you omit the two last arguments in the method call and the NonGeneric type is inferred (read about type inference under §7.5.2), both methods would look like this:

这意味着当你省略方法调用中的两个最后一个参数并推断出NonGeneric类型时(阅读§7.5.2下的类型推断),这两个方法看起来像这样:

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

Thus, they would be ambiguous...

因此,他们会模棱两可......

I would recommend reading §7.5.3.2 or even the whole §7.5.3 of the specification for further info.

我建议阅读§7.5.3.2甚至整个规范的§7.5.3以获取更多信息。

The solution is to either change your method declarations or remove the first overload altogether and let the second do the work :)

解决方案是更改方法声明或完全删除第一个重载,然后让第二个重做:)

#1


1  

It is ambiguous because you have two optional parameters in the second Ext1 extension method. Because both parameters are omitted in the first call, the compiler doesn't know which one you want to use.

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

From C# 4.0 Language Specification:

来自C#4.0语言规范:

§7.5.3 Overload resolution:

§7.5.3过载分辨率:

Given the set of applicable candidate function members, the best function member in that set is located. If the set contains only one function member, then that function member is the best function member. Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in §7.5.3.2. If there is not exactly one function member that is better than all other function members, then the function member invocation is ambiguous and a binding-time error occurs.

给定一组适用的候选函数成员,找到该集合中的最佳函数成员。如果集合只包含一个函数成员,那么该函数成员是最好的函数成员。否则,最佳函数成员是一个函数成员,它比给定参数列表中的所有其他函数成员更好,前提是使用§7.5.3.2中的规则将每个函数成员与所有其他函数成员进行比较。如果没有一个函数成员优于所有其他函数成员,则函数成员调用不明确并且发生绑定时错误。

Further, under §7.5.3.2 Better function member:

此外,根据§7.5.3.2更好的功能成员:

Optional parameters with no corresponding arguments are removed from the parameter list

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

What this means is that when you omit the two last arguments in the method call and the NonGeneric type is inferred (read about type inference under §7.5.2), both methods would look like this:

这意味着当你省略方法调用中的两个最后一个参数并推断出NonGeneric类型时(阅读§7.5.2下的类型推断),这两个方法看起来像这样:

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

Thus, they would be ambiguous...

因此,他们会模棱两可......

I would recommend reading §7.5.3.2 or even the whole §7.5.3 of the specification for further info.

我建议阅读§7.5.3.2甚至整个规范的§7.5.3以获取更多信息。

The solution is to either change your method declarations or remove the first overload altogether and let the second do the work :)

解决方案是更改方法声明或完全删除第一个重载,然后让第二个重做:)