Что такое группа методов в 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

Однако я удивился, что такое метод группы. Google не сильно помогает, ни MSDN .


62
Раздел 7.1 спецификации C # 3.0 определяет «группу методов».
Эрик Липперт

2
Я прочитал эту ошибку сейчас, когда вы пропустили скобки при вызове метода .
niico

2
Если бы у вас был список соответствующего типа делегата, например var list = new List<Func<string>>();, группа методов была бы пригодной для использования и list.Add(someObject.ToString);работала бы.
Джеппе Стиг Нильсен

Ответы:


332

Метод группы это имя для набора методов (которые могут быть только один) - то есть в теории ToStringметод может иметь несколько перегруженных (плюс любые методы расширения): ToString(), ToString(string format)и т.д. - следовательно , ToStringсамо по себе является «групповой метод».

Обычно он может преобразовать группу методов в (типизированный) делегат, используя разрешение перегрузки, но не в строку и т. Д .; это не имеет смысла.

Как только вы добавите скобки, снова; включается разрешение перегрузки, и вы однозначно определили вызов метода.


6
Что было бы типичным использованием группы методов? Поскольку (насколько я понимаю) оно имеет одно и то же имя, количество параметров и / или типы будут различаться. Таким образом, вы не можете вызвать более одного метода из группы методов, используя группу.
Андрей Ринея

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));
}

Я могу просто опустить имя переменной:

public List<string> GetStringStuff()
{
    return something.getStringsFromSomewhere.Select(DoSomethingToMyString);
}

112
Рекомендация ReSharper - это то, что привело меня к поиску группы методов. Это то, что ReSharper закончил с одним из моих выражений linq.
a_hardin

50
@a_hardin: ReSharper FTW! Я многое узнал о LINQ благодаря Resharper.
Джейсон Даун

3
«Более явная» версия только делает практически бесполезный метод-обертку. Анонимный метод-оболочка и DoSomethingToMyString оба принимают строку и возвращают строку. Символы "str => [...] (str)" - просто пустяки, которые, как мы надеемся, оптимизирует компилятор.
Грауль

6
Компилятор ничего не оптимизирует. Используя ILDASM, вы видите, что явная версия создает анонимный метод (лямбда-реализация) и передает его в Select (). Неявная версия передает DoSomethingToMyString напрямую.
Рольф

14
Напоминает мне о return flag == true ? true : false(лицевая сторона).
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 - группа методов), компилятор отклоняет это, даже если есть только одна перегрузка.
Рольф
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.