• Jobs
  • About Us
  • professionals
    • Home
    • Jobs
    • Courses and challenges
  • business
    • Home
    • Post vacancy
    • Our process
    • Pricing
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Salary Calculator

0

102
Views
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 3 years ago · Santiago Trujillo
1 answers
Answer question

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 3 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 Our process Sales
Legal
Terms and conditions Privacy policy
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recommend me some offers
I have an error