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&lt;Func&lt;string&gt;&gt;();,那么方法组就可以使用,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# 中的方法组是啥?的主要内容,如果未能解决你的问题,请参考以下文章

首次设置 AWS EB 时创建的默认安全组是啥?

C# 中的 .Any 和 .Count 更有效的是啥(扩展方法)[重复]

C#中的virtula是啥?

从 C# 中的矩形数组中提取一维数组的最佳方法是啥?

将整个对象转储到 C# 中的日志的最佳方法是啥?

从 C# 中的字符串中删除换行符的最快方法是啥?