Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.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# 编译器不明确的调用错误-具有Func的匿名方法和方法组<&燃气轮机;或行动_C#_Delegates - Fatal编程技术网

C# 编译器不明确的调用错误-具有Func的匿名方法和方法组<&燃气轮机;或行动

C# 编译器不明确的调用错误-具有Func的匿名方法和方法组<&燃气轮机;或行动,c#,delegates,C#,Delegates,我有一个场景,我想使用方法组语法而不是匿名方法(或lambda语法)来调用函数 该函数有两个重载,一个重载执行操作,另一个重载执行函数 我可以使用匿名方法(或lambda语法)愉快地调用这两个重载,但如果使用方法组语法,则会出现调用不明确的编译器错误。我可以通过显式转换到Action或Func来解决问题,但我认为这不是必需的 有人能解释为什么需要显式强制转换吗 下面是代码示例 class Program { static void Main(string[] args) {

我有一个场景,我想使用方法组语法而不是匿名方法(或lambda语法)来调用函数

该函数有两个重载,一个重载执行
操作
,另一个重载执行
函数

我可以使用匿名方法(或lambda语法)愉快地调用这两个重载,但如果使用方法组语法,则会出现调用不明确的编译器错误。我可以通过显式转换到
Action
Func
来解决问题,但我认为这不是必需的

有人能解释为什么需要显式强制转换吗

下面是代码示例

class Program
{
    static void Main(string[] args)
    {
        ClassWithSimpleMethods classWithSimpleMethods = new ClassWithSimpleMethods();
        ClassWithDelegateMethods classWithDelegateMethods = new ClassWithDelegateMethods();

        // These both compile (lambda syntax)
        classWithDelegateMethods.Method(() => classWithSimpleMethods.GetString());
        classWithDelegateMethods.Method(() => classWithSimpleMethods.DoNothing());

        // These also compile (method group with explicit cast)
        classWithDelegateMethods.Method((Func<string>)classWithSimpleMethods.GetString);
        classWithDelegateMethods.Method((Action)classWithSimpleMethods.DoNothing);

        // These both error with "Ambiguous invocation" (method group)
        classWithDelegateMethods.Method(classWithSimpleMethods.GetString);
        classWithDelegateMethods.Method(classWithSimpleMethods.DoNothing);
    }
}

class ClassWithDelegateMethods
{
    public void Method(Func<string> func) { /* do something */ }
    public void Method(Action action) { /* do something */ }
}

class ClassWithSimpleMethods
{
    public string GetString() { return ""; }
    public void DoNothing() { }
}
类程序
{
静态void Main(字符串[]参数)
{
ClassWithSimpleMethods ClassWithSimpleMethods=新类WithSimpleMethods();
ClassWithDelegateMethods ClassWithDelegateMethods=新类WithDelegateMethods();
//它们都是编译(lambda语法)
classWithDelegateMethods.Method(()=>classWithSimpleMethods.GetString());
方法(()=>classWithSimpleMethods.DoNothing());
//它们也可以编译(带有显式强制转换的方法组)
方法((Func)classWithSimpleMethods.GetString);
classWithDelegateMethods.Method((操作)ClassWithImpleMethods.DoNothing);
//这两个错误都与“不明确调用”(方法组)有关
classWithDelegateMethods.Method(classWithSimpleMethods.GetString);
classWithDelegateMethods.Method(classWithSimpleMethods.DoNothing);
}
}
使用DelegateMethods初始化类
{
公共无效方法(Func Func){/*执行操作*/}
public void方法(Action Action){/*做点什么*/}
}
使用简单方法初始化类
{
公共字符串GetString(){return”“;}
public void DoNothing(){}
}
C#7.3更新
根据下面2019年3月20日的评论(在我发布这个问题九年之后!),这段代码从C#7.3开始编译,这要归功于。

Func和
Action
的重载类似于

string Function()//Func
{
}
void Function()//操作
{
}

如果您注意到,编译器不知道调用哪一个,因为它们只在返回类型上有所不同。

EDIT:我想我知道了

正如zinglon所说,这是因为存在从
GetString
Action
的隐式转换,即使编译时应用程序会失败。以下是第6.6节的介绍,重点是(我的):

存在隐含转换(§6.1) 从方法组(§7.1)到 兼容的委托类型。给予 委托类型D和表达式E 被归类为方法组, 存在来自E的隐式转换 如果E至少包含一个方法,则返回D 这在其正常形式下是适用的 (§7.4.3.1)添加到参数列表中 使用参数构造 D的类型和修饰符,如所述 在下文中

现在,我被第一句话弄糊涂了——这句话讲的是转换为兼容的委托类型
Action
不是
GetString
method组中任何方法的兼容委托,而是
GetString()
方法以其正常形式适用于使用参数类型和D的修饰符构造的参数列表。请注意,这并没有涉及D的返回类型。这就是为什么它会混淆。。。因为在应用转换时,它只检查
GetString()
的委托兼容性,而不检查其存在性

我认为简单地将重载排除在等式之外是很有启发性的,看看转换的存在和适用性之间的差异是如何体现出来的。下面是一个简短但完整的示例:

using System;

class Program
{
    static void ActionMethod(Action action) {}
    static void IntMethod(int x) {}

    static string GetString() { return ""; }

    static void Main(string[] args)
    {
        IntMethod(GetString);
        ActionMethod(GetString);
    }
}
Main
中的两个方法调用表达式都不会编译,但错误消息不同。下面是一个用于
IntMethod(GetString)

Test.cs(12,9):错误CS1502:最佳 重载方法匹配 “Program.IntMethod(int)”有一些 无效参数

换句话说,规范第7.4.3.1节找不到任何适用的功能成员

下面是
ActionMethod(GetString)
的错误:

cs(13,22):错误CS0407:'string Program.GetString()具有错误的 返回类型

这一次,它已经找到了想要调用的方法,但是它没有执行所需的转换。不幸的是,我找不到规范中执行最终检查的位置——看起来可能在7.5.5.1中,但我看不到确切的位置


旧的答案被删除了,除了这一点——因为我希望埃里克能够解释这个问题的“为什么”

还在看。。。同时,如果我们说“Eric Lippert”三次,你认为我们会得到访问(从而得到答案)吗?

使用
Func
Action
(明显不同于
Action
Func
)在
类中使用delegateMethods
消除歧义

Action
Func
之间也会出现歧义

我还得到了模糊性错误:

class Program
{ 
    static void Main(string[] args) 
    { 
        ClassWithSimpleMethods classWithSimpleMethods = new ClassWithSimpleMethods(); 
        ClassWithDelegateMethods classWithDelegateMethods = new ClassWithDelegateMethods(); 

        classWithDelegateMethods.Method(classWithSimpleMethods.GetOne);
    } 
} 

class ClassWithDelegateMethods 
{ 
    public void Method(Func<int> func) { /* do something */ }
    public void Method(Func<string> func) { /* do something */ } 
}

class ClassWithSimpleMethods 
{ 
    public string GetString() { return ""; } 
    public int GetOne() { return 1; }
} 
类程序
{ 
静态void Main(字符串[]参数)
{ 
ClassWithSimpleMethods ClassWithSimpleMethods=新类WithSimpleMethods();
ClassWithDelegateMethods ClassWithDelegateMethods=新类WithDelegateMethods();
classWithDelegateMethods.Method(classWithSimpleMethods.GetOne);
} 
} 
使用DelegateMethods初始化类
{ 
公共无效方法(Func Func){/*执行操作*/}
公共无效方法(Func Func){/*执行操作*/}
}
使用简单方法初始化类
{ 
公共字符串GetString(){return”“;}
public int GetOne(){return 1;}
} 
class Program
{ 
    static void Main(string[] args) 
    { 
        ClassWithSimpleMethods classWithSimpleMethods = new ClassWithSimpleMethods(); 
        ClassWithDelegateMethods classWithDelegateMethods = new ClassWithDelegateMethods(); 

        classWithDelegateMethods.Method(classWithSimpleMethods.GetOne);
    } 
} 

class ClassWithDelegateMethods 
{ 
    public void Method(Func<int> func) { /* do something */ }
    public void Method(Func<string> func) { /* do something */ } 
}

class ClassWithSimpleMethods 
{ 
    public string GetString() { return ""; } 
    public int GetOne() { return 1; }
} 
class Program
{
    static void Main(string[] args)
    {
        ClassWithSimpleMethods classWithSimpleMethods = new ClassWithSimpleMethods();
        ClassWithDelegateMethods classWithDelegateMethods = new ClassWithDelegateMethods();

        //The call is ambiguous between the following methods or properties: 
        //'test.ClassWithDelegateMethods.Method(System.Func<int,int>)' 
        //and 'test.ClassWithDelegateMethods.Method(test.ClassWithDelegateMethods.aDelegate)'
        classWithDelegateMethods.Method(classWithSimpleMethods.GetX);
    }
}

class ClassWithDelegateMethods
{
    public delegate string aDelegate(int x);
    public void Method(Func<int> func) { /* do something */ }
    public void Method(Func<string> func) { /* do something */ }
    public void Method(Func<int, int> func) { /* do something */ }
    public void Method(Func<string, string> func) { /* do something */ }
    public void Method(aDelegate ad) { }
}

class ClassWithSimpleMethods
{
    public string GetString() { return ""; }
    public int GetOne() { return 1; }
    public string GetX(int x) { return x.ToString(); }
} 
class Program
{
    delegate void D1();
    delegate string D2();
    static string X() { return null; }
    static void Y(D1 d1) {}
    static void Y(D2 d2) {}
    static void Main()
    {
        Y(X);
    }
}
void Q(Expression<Func<string>> f){}
string M(int x) { ... }
...
int y = 123;
Q(()=>M(y++));