Ответ 1
Вы используете преобразование группы методов для создания Func<long, long, bool>
используемого для параметра comparerFunc
. К сожалению, в спецификации С# 5 в настоящее время требуется, чтобы каждый экземпляр делегата создавал новый экземпляр делегата. Из раздела 6.6 спецификации С# 5, описывающего оценку времени выполнения преобразования группы методов:
Выделяется новый экземпляр типа делегата. Если для размещения нового экземпляра недостаточно памяти, генерируется исключение System.OutOfMemoryException и дальнейшие шаги не выполняются.
Раздел анонимных преобразований функций (6.5.1) включает в себя следующее:
Преобразования семантически идентичных анонимных функций с одним и тем же (возможно, пустым) набором захваченных внешних экземпляров переменной для тех же типов делегатов разрешены (но не обязательно) для возврата одного и того же экземпляра делегата.
... но ничего подобного для конверсий групп методов.
Это означает, что этому коду разрешено оптимизировать использование одного экземпляра делегата для каждого из задействованных делегатов - и Roslyn.
Func<Guid[], int> func = x => Utils.Foo(x, (a, b) => Utils.ComparerFunc(a, b));
Другой вариант - выделить Func<long, long, bool>
один раз и сохранить его в локальной переменной. Локальная переменная должна быть захвачена с помощью выражения лямбда, что предотвращает кэширование Func<Guid[], int>
- это означает, что если вы много раз выполняли Main
, вы создавали бы два новых делегата для каждого вызова, тогда как более раннее решение будет кэшировать, насколько это разумно. Код проще:
Func<long, long, bool> comparer = Utils.ComparerFunc;
Func<Guid[], int> func = x => Utils.Foo(x, comparer);
var guids = new Guid[10];
for (int i = 0; i < 1000000; i++)
{
int a = func(guids);
}
Все это меня огорчает, и в последнем выпуске стандарта ECMA С# компилятору будет разрешено кэшировать результат преобразований группы методов. Я не знаю, когда и будет ли это делать.