C#中的方法组是什么?


351

在以下情况下,我经常遇到诸如“无法从“方法组”转换为“字符串””之类的错误:

var list = new List<string>();
// ... snip
list.Add(someObject.ToString);

当然,最后一行有一个错字,因为我忘了后面的调用括号ToString。正确的格式为:

var list = new List<string>();
// ... snip
list.Add(someObject.ToString()); // <- notice the parentheses

但是我开始想知道什么是方法组。谷歌并没有多大帮助,也不是MSDN


62
C#3.0规范的7.1节定义了“方法组”。
埃里克·利珀特

2
我现在读到此错误,因为您在调用方法时错过了方括号
niico

2
如果您有一个合适的委托人类型的列表,例如var list = new List<Func<string>>();,则该方法组将是可用的并且list.Add(someObject.ToString);可以使用。
杰普·斯蒂格·尼尔森

Answers:


332

方法组是一个名称的一套方法(可能是只有一个) -即理论上的ToString方法可以有多个重载(加任何扩展方法)ToString()ToString(string format)等-因此ToString本身是一个“方法组”。

它通常可以使用重载解析将方法组转换为(类型化的)委托,但不能转换为字符串等。这没有意义。

一旦加上括号,再次;重载解析开始,您已经明确确定了方法调用。


6
方法组的典型用途是什么?由于(据我所知)它具有相同的名称,因此参数计数和/或类型将有所不同。因此,您不能使用该组从方法组中调用多个方法。
2009年

32
它纯粹是“我知道方法名是什么,但我不知道签名”的编译器术语。它在运行时不存在。AFAIK,方法组本身的唯一用法(无括号等)是在委托构造期间使用。
马克·格雷韦尔

20
ECMA 334v4§14.1:方法组可以在调用表达式(第14.5.5节)中使用,在委托创建表达式(第14.5.10.3节)中使用,或隐式转换为兼容的委托类型。在任何其他上下文中,归类为方法组的表达式都会导致编译时错误。
马克·格雷韦尔

1
对方法组的协方差和反方差支持允许将方法签名与委托类型进行匹配。这使您不仅可以将具有匹配签名的方法分配给委托,还可以将返回派生类型(协方差)更多的参数或接受派生类型比(委托方)指定的参数少的参数的方法分配给委托。有关更多信息,请参见代表中的差异(C#)和使用代表中的差异(C#)。
user2211290

162

另外,如果您使用的是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);
}

112
ReSharper的建议促使我搜索方法组。这就是ReSharper最终对我的linq表达式之一所做的事情。
a_hardin

50
@a_hardin:ReSharper FTW!感谢Resharper,我对LINQ有了很多了解。
杰森·唐

3
“更明确的”版本仅使一种基本上无用的包装器方法。匿名包装器方法和DoSomethingToMyString都接受一个字符串并返回一个字符串。“ str => [...](str)”字符只是残酷的,编译器有望对其进行优化。
Grault

6
编译器没有优化。使用ILDASM,您会看到显式版本创建了一个匿名方法(lambda实现)并将其传递给Select()。隐式版本直接传递DoSomethingToMyString。
罗夫2014年

14
让我想起了return flag == true ? true : false(facepalm)。
ErikE

24

您可以将方法组转换为委托。

委托签名从组中选择1种方法。

本示例选择ToString()采用字符串参数的重载:

Func<string,string> fn = 123.ToString;
Console.WriteLine(fn("00000000"));

本示例选择ToString()不带参数的重载:

Func<string> fn = 123.ToString;
Console.WriteLine(fn());

21

您的MSDN搜索中的第一个结果是:

方法组标识一个要调用的方法或一组重载方法,从中可以选择要调用的特定方法

我的理解是,基本上是因为当您只写时someInteger.ToString,它可能是指:

Int32.ToString(IFormatProvider) 

或者可以参考:

Int32.ToString()

因此它称为方法组。


18

ToString函数具有许多重载-方法组将是该函数的所有不同重载组成的组。


2
是的,重点是方法组是编译时构造。编译器根据使用消息组的上下文选择一种方法重载。例如:您不能写“ var x = Foo;” (其中Foo是方法组),即使只有一个重载,编译器也会拒绝此操作。
罗夫2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.