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