gpt4 book ai didi

c# - Assembly.GetTypes() 的行为在 Visual Studio 2015 中发生了变化

转载 作者:IT王子 更新时间:2023-10-29 04:21:57 25 4
gpt4 key购买 nike

我昨天在 Visual Studio 2015 中打开了我们的解决方案,我们的一些单元测试(在 Visual Studio 2013 中运行良好)开始失败。深入挖掘我发现这是因为调用GetTypes()在一个程序集上返回不同的结果。我已经能够创建一个非常简单的测试用例来说明它。

在 Visual Studio 2013 和 2015 中,我使用 .NET Framework 4.5.2 创建了一个新的控制台应用程序。我在两个项目中都放入了以下代码。

class Program
{
static void Main(string[] args)
{
var types = typeof(Program).Assembly.GetTypes()
.Where(t => !t.IsAbstract && t.IsClass);

foreach (var type in types)
{
Console.WriteLine(type.FullName);
}

Console.ReadKey();
}
}

当我在 Visual Studio 2013 中运行时,我得到以下输出(如预期的那样)。

VS2013Example.Program

当我在 Visual Studio 2015 中运行时,我得到以下输出(与预期不同)。

VS2015Example.Program

VS2015Example.Program+<>c

那是什么VS2015Example.Program+<>c类型?结果是.Where()里面的lambda方法。是的,没错,本地 lambda 以某种方式作为一种类型公开。如果我注释掉 .Where()在 VS2015 中,我不再得到第二行。

我使用 Beyond Compare 比较了这两个 .csproj 文件,但唯一的区别是 VS 版本号、项目 GUID、默认命名空间和程序集的名称,而 VS2015 文件引用了 System.Net。 VS2013 没有的 Http。

有没有人看到这个?

有没有人解释为什么局部变量会在程序集级别公开为类型?

最佳答案

Has anyone else seen this?

是的,这是由提升 lambda 表达式的新编译器行为引起的。

以前,如果 lambda 表达式没有捕获任何局部变量,它将作为静态方法缓存在调用站点,这使得编译器团队需要跳一些圈子才能正确对齐方法参数和这个 参数。 Roslyn 中的新行为是所有 lambda 表达式都被提升到显示类中,其中委托(delegate)作为显示类中的实例方法公开,而不管它是否捕获任何局部变量。

如果您在 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);

有关更多信息,请参阅我的问题 Delegate caching behavior changes in Roslyn

关于c# - Assembly.GetTypes() 的行为在 Visual Studio 2015 中发生了变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31542076/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com