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