Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 带有默认参数和泛型的方法解决问题_C#_.net_Generics_Overload Resolution_Default Parameters - Fatal编程技术网

C# 带有默认参数和泛型的方法解决问题

C# 带有默认参数和泛型的方法解决问题,c#,.net,generics,overload-resolution,default-parameters,C#,.net,Generics,Overload Resolution,Default Parameters,使用.NET4时,编译器无法解析下面示例中的第一个方法调用,这让我感到困惑 using System; namespace MethodResolutionTest { class Program { static void Main(string[] args) { NonGeneric foo = null; // ambiguous foo.Ext1(x =>

使用.NET4时,编译器无法解析下面示例中的第一个方法调用,这让我感到困惑

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;
        }
    }
}
使用系统;
名称空间方法ResolutionTest
{
班级计划
{
静态void Main(字符串[]参数)
{
非通用foo=null;
//暧昧
Ext1(x=>newnongeneric());
//解析为第一个Ext1
Ext1(x=>newnongeneric(),1);
//解析为第一个Ext2
Ext2(x=>newnongeneric());
//解析为第一个Ext2
Ext2(x=>newnongeneric(),1);
//解析为第二个Ext2
Ext2(x=>“foo”);
//解析为第二个Ext2
Ext2(x=>“foo”,1);
//解析为第一个Ext3
Ext3(x=>newnongeneric());
//解析为第一个Ext3
Ext3(x=>newnongeneric(),1);
//解析为第二个Ext3
Ext3(x=>“foo”);
//解析为第二个Ext3
Ext3(x=>“foo”,1);
}
}
公共类非通用
{
}
公共类泛型:非泛型
{
}
公共静态类扩展1
{
公共静态非通用Ext1(此非通用first,Func getNext,int i=0)
{
返回null;
}
公共静态泛型Ext1(此非泛型优先,Func getNext,int i=0,字符串s=null)
{
返回null;
}
}
//Extensions2和Extensions1之间的唯一区别是,第二个重载不再具有默认的字符串参数
公共静态类扩展2
{
公共静态非泛型Ext2(此非泛型优先,Func getNext,int i=0)
{
返回null;
}
公共静态泛型Ext2(此非泛型优先,Func getNext,int i=0)
{
返回null;
}
}
//Extensions3显式定义了一个不默认int参数的重载
公共静态类扩展3
{
公共静态非泛型Ext3(此非泛型优先,Func getNext)
{
返回Ext3(first、getNext、default(int));
}
公共静态非泛型Ext3(此非泛型优先,Func getNext,int i=0)
{
返回null;
}
公共静态泛型Ext3(此非泛型优先,Func getNext,int i=0)
{
返回null;
}
}
}

有人能解释一下吗?我怀疑除了修改API来帮助编译器(根据上面的
Extensions3
)之外,我真的没有其他方法,但是如果有更简单/更好的方法,我很乐意听到它。

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

发件人:

§7.5.3过载分辨率

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

此外,在§7.5.3.2更好的功能成员下:

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

这意味着,当您省略方法调用中的最后两个参数,并推断出
非泛型
类型时(请阅读§7.5.2下的类型推断),这两种方法将如下所示:

Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext)
Ext1(此非泛型优先,Func getNext)
因此,它们将是模棱两可的

我建议阅读本规范第7.5.3.2节,甚至是整个第7.5.3节,以了解更多信息


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

编译器在
Extensions2
Extensions3
场景中都选择了fine,所以这并不是那么简单。另外,如果我不想要默认的
int
参数,那么我显然不会一开始就这样声明它!但是,如果省略了可选参数,为什么有两个具有可选参数的方法实际上是不明确的呢?如果您绝对需要这两种方法,则需要使用
Extensions2
Extensions3
解决方案。@khellang:您能否指出导致这种行为的C语言规范部分(重载解析歧义)?@KonstantinOznobihin检查修改后的答案:)@khellang:让我怀疑的是“§7.5.3.2更好的函数成员”,第一条打破僵局的规则是“如果MP是非泛型方法,MQ是泛型方法,那么MP比MQ更好。”我已经阅读了几个规范部分,但仍然无法找到解释为什么泛型方法会导致歧义(这就是为什么我问了你一个问题)。