Почему Action.Method.IsStatic отличается между Visual Studio 2013 и 2015 для определенных лямбда-выражений

Учитывая приведенную ниже консольную программу:

class Program
{
    private static string _value;
    static void Main(string[] args)
    {
        var t = new Action(() => _value = "foo");
        Console.Out.WriteLine("t.Method.IsStatic: {0}", t.Method.IsStatic);
    } 
}

При компиляции с .Net 4.5.2 с использованием VS 2013 он будет печатать

t.Method.IsStatic: true

При компиляции с .Net 4.5.2 с использованием VS 2015 он будет печатать

t.Method.IsStatic: false

Из этого вопроса я Я понимаю, что происходит, но я не понимаю, почему происходит изменение поведения между версиями VS. Насколько я понимаю, вывод 2013 года правильный.


person MattS    schedule 11.05.2016    source источник


Ответы (2)


Проверьте ответ по следующей ссылке: Делегировать изменения поведения кэширования в Roslyn

В основном, что изменилось, и я цитирую @Yuzal из связанного ответа:

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

И под отображаемым классом он имел в виду сгенерированный закрытый запечатанный класс, внутри которого инкапсулируется метод экземпляра, вызываемый делегатом действия.

Почему было внесено изменение? Цитируя @Kevin Pilch-Bisson (член команды C# IDE):

Причина, по которой это происходит быстрее, заключается в том, что вызовы делегатов оптимизированы для методов экземпляра и имеют для них место в стеке. Чтобы вызвать статический метод, они должны изменить параметры.

Так что в основном комментарий говорит сам за себя. Разница в поведении, которую вы видите в приведенном выше примере, заключается в том, что они заметили, что если делегат Action вызывает методы экземпляра, это быстрее, чем вызов статических методов, независимо от того, захватывает ли лямбда переменные или нет.

person Siraj Mansour    schedule 11.05.2016
comment
Да, это проблема. К сожалению, это вызывает странные проблемы, если вы используете WeakReferences. - person MattS; 11.05.2016
comment
@MattS хммм, можешь поподробнее об этом? - person Siraj Mansour; 12.05.2016
comment
@MattS Когда вы полагаетесь на недокументированное поведение, вы должны ожидать проблем. - person svick; 14.05.2016

Из этого следует, что поведение изменилось между компилятором 2013 и Rosyln. Очень надоедливый.

person MattS    schedule 11.05.2016