C# 中的方法组是啥?
Posted
技术标签:
【中文标题】C# 中的方法组是啥?【英文标题】:What is a method group in C#?C# 中的方法组是什么? 【发布时间】:2010-10-27 13:46:40 【问题描述】:我经常遇到诸如“无法从'方法组'转换为'字符串'”这样的错误:
var list = new List<string>();
// ... snip
list.Add(someObject.ToString);
当然,最后一行有错字,因为我忘记了ToString
之后的调用括号。正确的形式是:
var list = new List<string>();
// ... snip
list.Add(someObject.ToString()); // <- notice the parentheses
但是我开始想知道什么是方法组。 Google 没有多大帮助,MSDN.
【问题讨论】:
C# 3.0 规范的第 7.1 节定义了“方法组”。 我现在读到这个错误是因为你在调用方法时错过了括号。 如果您有一个适当的委托类型列表,例如var list = new List<Func<string>>();
,那么方法组就可以使用,list.Add(someObject.ToString);
就可以工作。
【参考方案1】:
方法组是一组方法的名称(可能只是一个)- 即理论上ToString
方法可能有多个重载(加上任何扩展方法):@987654322 @、ToString(string format)
等 - 因此 ToString
本身就是一个“方法组”。
它通常可以通过重载解析将方法组转换为(类型化的)委托 - 但不能转换为字符串等;这没有意义。
添加括号后,再次;重载决议开始了,你已经明确地确定了一个方法调用。
【讨论】:
方法组的典型用途是什么?由于(据我所知)它具有相同的名称,因此参数计数和/或类型会有所不同。因此,您不能使用该组从方法组中调用多个方法。 纯粹是编译器术语,意思是“我知道方法名是什么,但我不知道签名”;它在运行时不存在。 AFAIK,方法组单独使用(无括号等)的唯一用途是在委托构造期间。 ECMA 334v4 §14.1:方法组可用于调用表达式 (§14.5.5)、委托创建表达式 (§14.5.10.3) 或隐式转换为兼容的委托类型。在任何其他上下文中,归类为方法组的表达式会导致编译时错误。 对方法组的协变和逆变支持允许将方法签名与委托类型匹配。这使您不仅可以将具有匹配签名的方法分配给委托,还可以分配返回更多派生类型(协变)或接受派生类型(逆变)少于委托类型指定的参数的方法。有关详细信息,请参阅委托中的差异 (C#) 和在委托中使用差异 (C#)。 100% 的时候,当我收到此错误时,我忘记了方法调用上的括号,因为我认为它是一个属性。像“你忘了 ()”这样的错误实际上在 99% 的时间里都是有用的,哈哈【参考方案2】:你的 MSDN 搜索的第一个结果是:
方法组标识一个 调用的方法或一组 从中重载的方法 选择要调用的特定方法
我的理解是,基本上是因为你刚才写someInteger.ToString
时,可能指的是:
Int32.ToString(IFormatProvider)
或者可以参考:
Int32.ToString()
所以称为方法组。
【讨论】:
【参考方案3】:ToString
函数有许多重载 - 方法组是由该函数的所有不同重载组成的组。
【讨论】:
是的,关键是方法组是一个编译时构造。编译器根据使用消息组的上下文选择一种方法重载。例如:你不能写“var x = Foo;” (其中 Foo 是一个方法组),即使只有一个重载,编译器也会拒绝它。【参考方案4】:此外,如果您使用的是 LINQ,您显然可以执行类似 myList.Select(methodGroup)
的操作。
所以,例如,我有:
private string DoSomethingToMyString(string input)
// blah
而不是像这样明确说明要使用的变量:
public List<string> GetStringStuff()
return something.getStringsFromSomewhere.Select(str => DoSomethingToMyString(str));
我可以省略 var 的名称:
public List<string> GetStringStuff()
return something.getStringsFromSomewhere.Select(DoSomethingToMyString);
【讨论】:
ReSharper 的建议是促使我搜索方法组的原因。这就是 ReSharper 最终对我的一个 linq 表达式所做的事情。 @a_hardin:ReSharper FTW!感谢 Resharper,我学到了很多关于 LINQ 的知识。 “更明确”的版本只是制作了一种本质上无用的包装方法。匿名包装方法和 DoSomethingToMyString 都接受一个字符串并返回一个字符串。 “str => [...](str)” 字符只是编译器希望优化掉的杂乱无章。 编译器不优化。使用 ILDASM,您会看到显式版本创建了一个匿名方法(lambda 实现)并将其传递给 Select()。隐式版本直接传递 DoSomethingToMyString。 让我想起了return flag == true ? true : false
(捂脸)。【参考方案5】:
您可以将方法组转换为委托。
委托签名从组中选择 1 个方法。
这个例子选择了ToString()
重载,它带有一个字符串参数:
Func<string,string> fn = 123.ToString;
Console.WriteLine(fn("00000000"));
此示例选择不带参数的 ToString()
重载:
Func<string> fn = 123.ToString;
Console.WriteLine(fn);
【讨论】:
以上是关于C# 中的方法组是啥?的主要内容,如果未能解决你的问题,请参考以下文章