Передача метода расширения методу, ожидающему делегата. Как это работает? - PullRequest
11 голосов
/ 20 июля 2010

Так что на работе я использовал API, который мы не писали, и один из методов взял делегата.По той или иной причине мне пришла идея, что у меня есть метод расширения, который подходит под эту сигнатуру, поэтому мне было интересно, сработает ли он.Я был уверен, что к моему большому удивлению это не так сильно.Позвольте мне продемонстрировать:

Скажем, у меня есть эти классы:

public interface IMyInterface
{

}

public class MyClass : IMyInterface 
{ 

}

public static class Extensions
{
    public static string FuncMethod(this IMyInterface imy, int x)
    {
        return x.ToString();
    }
}

Теперь, допустим, у меня где-то есть сигнатура метода, которая выглядит так:

    private static void Method(Func<int, string> func)
    {

    }

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

var instance = new MyClass();
Method(instance.FuncMethod);

Мой вопрос, как это работает?Что генерирует компилятор для меня, чтобы сделать это приемлемым.Фактическая сигнатура метода Extension берет экземпляр IMyInterface, но Func не так, что здесь происходит для меня за кулисами?

Ответы [ 2 ]

11 голосов
/ 20 июля 2010

Методы экземпляра реализованы в виде скрытого параметра this.

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

Обратите внимание, что это невозможно сделать с типами значений .

5 голосов
/ 20 июля 2010

Я не знаю точно, что делает компилятор, чтобы разрешить эти сценарии, но ожидания кажутся разумными.Возможно, этот пример кода поможет понять концепцию.

MyClass instance = new MyClass();
Func<int, string> f1 = instance.FuncMethod;
Func<int, string> f2 = (i) => instance.FuncMethod(i);
Func<int, string> f3 = (i) => Extensions.FuncMethod(instance, i);
...