Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

283
Views
Comportamiento de Assembly.GetTypes() cambiado en Visual Studio 2015

Ayer abrí nuestra solución en Visual Studio 2015 y algunas de nuestras pruebas unitarias (que funcionaron bien en Visual Studio 2013) comenzaron a fallar. Profundice más y descubrí que se debía a que llamar a GetTypes() en un ensamblado arrojaba resultados diferentes. He podido crear un caso de prueba muy simple para ilustrarlo.

Tanto en Visual Studio 2013 como en 2015, creé una nueva aplicación de consola usando .NET Framework 4.5.2. Puse el siguiente código en ambos proyectos.

 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(); } }

Cuando ejecuto Visual Studio 2013, obtengo el siguiente resultado (como se esperaba).

VS2013Ejemplo.Programa

Cuando ejecuto Visual Studio 2015, obtengo el siguiente resultado (no como se esperaba).

VS2015Ejemplo.Programa

VS2015Ejemplo.Programa+<>c

Entonces, ¿qué es ese VS2015Example.Program+<>c ? Resulta que es la lambda dentro del método .Where() . Sí, así es, de alguna manera esa lambda local está siendo expuesta como un tipo. Si comento el .Where() en VS2015, ya no obtengo esa segunda línea.

Usé Beyond Compare para comparar los dos archivos .csproj, pero las únicas diferencias son el número de versión de VS, el GUID del proyecto, los nombres del espacio de nombres predeterminado y el ensamblado, y el VS2015 tenía una referencia a System.Net.Http que el VS2013 uno no lo hizo.

¿Alguien más ha visto esto?

¿Alguien tiene una explicación de por qué una variable local estaría expuesta como un tipo en el nivel de ensamblaje?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

¿Alguien más ha visto esto?

Sí, esto se debe al nuevo comportamiento del compilador para levantar expresiones lambda.

Anteriormente, si una expresión lambda no capturaba ninguna variable local, se almacenaba en caché como un método estático en el sitio de la llamada, lo que hacía que el equipo de compilación tuviera que hacer algunos cambios para alinear correctamente los argumentos del método y el parámetro this . El nuevo comportamiento en Roslyn es que todas las expresiones lambda se elevan a una clase de visualización, donde el delegado se expone como un método de instancia en la clase de visualización, sin tener en cuenta si captura alguna variable local.

Si descompila su método en Roslyn, verá esto:

 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; } }

¿Dónde está el antiguo compilador? Verías esto:

 [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; }

Puede obtener el resultado deseado filtrando las clases que tienen el atributo CompilerGenerated adjunto:

 var types = typeof(Program) .Assembly .GetTypes() .Where(t => !t.IsAbstract && t.IsClass && Attribute.GetCustomAttribute( t, typeof (CompilerGeneratedAttribute)) == null);

Para obtener más información, consulte mi pregunta Cambios en el comportamiento de almacenamiento en caché del delegado en Roslyn

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!