Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

183
Vistas
Omitir la comprobación de IDisposable de foreach con un enumerador de tipo de valor genérico

Tengo un resultado confuso con genéricos y restricciones que estoy tratando de entender. Dejando de lado si algo de esto es una buena idea o no, este código:

 using System; using System.Collections.Generic; public interface IValueEnumerator<T, EnumeratorType> where EnumeratorType : struct { T Current { get; } bool MoveNext(); EnumeratorType GetEnumerator(); } public struct MyEnumerable : IValueEnumerator<int, MyEnumerable> { private int index; private int count; public MyEnumerable(int count) { this.index = -1; this.count = count; } public bool MoveNext() => ++index < count; public MyEnumerable GetEnumerator() => this; public int Current => index; } public class Program { public static int Iterate<T>(T enumerable) where T : struct, IValueEnumerator<int, T> { int z = 0; foreach (int y in enumerable) z += y; return z; } public static void Main() { var prevMem = System.GC.GetAllocatedBytesForCurrentThread(); MyEnumerable z = new MyEnumerable(); int result = Iterate(z); long diff = GC.GetAllocatedBytesForCurrentThread() - prevMem; Console.WriteLine($"Result was {result}"); Console.WriteLine($"{diff} extra bytes allocated"); } }

Produce esta salida:

 Result was 0 24 extra bytes allocated

Dentro de Iterate , el bucle foreach está generando código para encuadrar el enumerador y verificar si implementa IDisposable . El boxeo está provocando la asignación.

Si cambio la restricción de tipo para que Iterate esté where T : struct, IValueEnumerator<int, MyEnumerable> el compilador parece reconocer que el iterador no puede implementar IDisposable y omite el encuadre y no obtengo asignaciones:

 Result was 0 0 extra bytes allocated

He probado una variedad de compiladores y todos tienen el mismo comportamiento.

¿Es esto por diseño? Creo que la cláusula de restricción original sería suficiente para que el compilador no genere la verificación IDisposable . ¿Hay restricciones adicionales que podría agregar para que siga siendo genérico pero que el compilador no implemente la verificación IDisposable en el foreach, o al menos no haga el boxeo?

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

Bien, he descubierto esto, tanto por qué estaba sucediendo como una solución.

Primero, esto solo sucede en la depuración, no en el lanzamiento. En el lanzamiento, parece que el compilador es lo suficientemente inteligente como para evitar la verificación adicional de IDisposable .

A continuación, la restricción where T : struct, IValueEnumerator<int, MyEnumerable> le dice al compilador que T será un tipo de valor pero no le dice que T no será IDisposasble . En la depuración, parece que la misma función genérica debe poder ejecutarse en cualquier tipo permitido por las restricciones y algunos de esos tipos pueden implementar IDisposable y otros no. La ruta de menor resistencia para el compilador es simplemente encuadrar el valor y verificar si es un IDisposable .

Desafortunadamente, no hay nada como where T : not IDisposable para asegurarle al compilador que no tendrá que deshacerse del enumerador. Sin embargo, podemos ir por el otro lado y hacer que la interfaz implemente IDisposable . Luego, el compilador sabe que T es desechable y puede llamar a Dispose() sin encasillarlo primero.

Es decir, no causará ningún encasillamiento ni asignaciones adicionales en la depuración si la interfaz se ve así:

 public interface IValueEnumerator<T, EnumeratorType> : IDisposable where EnumeratorType : struct, IDisposable { T Current { get; } bool MoveNext(); EnumeratorType GetEnumerator(); }

La estructura de implementación tiene que agregar un método Dispose() vacío al que llamará el foreach después de su iteración, lo cual es menos eficiente que cuando el compilador sabe que el enumerador definitivamente no implementa IDisposable y puede omitir todo eso. Pero evita cualquier boxeo y no se hacen asignaciones.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda