Ответ 1
Кто-нибудь еще видел это?
Да, это вызвано новым поведением компилятора для подъема лямбда-выражений.
Раньше, если лямбда-выражение не фиксировало каких-либо локальных переменных, оно было бы кэшировано как статический метод на сайте вызова, что заставило команду компилятора перескакивать некоторые обручи, чтобы правильно выровнять аргументы метода и this
. Новое поведение в Roslyn заключается в том, что все лямбда-выражения поднимаются в класс отображения, где делегат отображается как метод экземпляра в классе отображения, не обращая внимания на то, фиксирует ли он какие-либо локальные переменные.
Если вы декомпилируете свой метод в Roslyn, вы увидите следующее:
private static void Main(string[] args)
{
IEnumerable<Type> arg_33_0 = typeof(Program).Assembly.GetTypes();
Func<Type, bool> arg_33_1;
if (arg_33_1 = Program.<>c.<>9__0_0 == null)
{
arg_33_1 = Program.<>c.<>9__0_0 =
new Func<Type, bool>(Program.<>c.<>9.<Main>b__0_0);
}
using (IEnumerator<Type> enumerator = arg_33_0.Where(arg_33_1).GetEnumerator())
{
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current.FullName);
}
}
Console.ReadKey();
}
[CompilerGenerated]
[Serializable]
private sealed class <>c
{
public static readonly Program.<>c <>9;
public static Func<Type, bool> <>9__0_0;
static <>c()
{
// Note: this type is marked as 'beforefieldinit'.
Program.<>c.<>9 = new Program.<>c();
}
internal bool <Main>b__0_0(Type t)
{
return !t.IsAbstract && t.IsClass;
}
}
Где со старым компилятором вы увидите следующее:
[CompilerGenerated]
private static Func<Type, bool> CS$<>9__CachedAnonymousMethodDelegate1;
private static void Main(string[] args)
{
IEnumerable<Type> arg_34_0 = typeof(Program).Assembly.GetTypes();
if (Program.CS$<>9__CachedAnonymousMethodDelegate1 == null)
{
Program.CS$<>9__CachedAnonymousMethodDelegate1 =
new Func<Type, bool>(Program.<Main>b__0);
}
IEnumerable<Type> types =
arg_34_0.Where(Program.CS$<>9__CachedAnonymousMethodDelegate1);
foreach (Type type in types)
{
Console.WriteLine(type.FullName);
}
Console.ReadKey();
}
[CompilerGenerated]
private static bool <Main>b__0(Type t)
{
return !t.IsAbstract && t.IsClass;
}
Вы можете получить желаемый результат, отфильтровывая классы, у которых есть атрибут CompilerGenerated
, прикрепленный к ним:
var types = typeof(Program)
.Assembly
.GetTypes()
.Where(t => !t.IsAbstract &&
t.IsClass &&
Attribute.GetCustomAttribute(
t, typeof (CompilerGeneratedAttribute)) == null);
Подробнее см. мой вопрос Делегировать изменения поведения кэширования в Roslyn