for - codigos de programacion c#
Extraños resultados de cobertura de prueba para el bloque de iteradores, ¿por qué no se ejecutan estas declaraciones? (1)
Uno de los problemas con los métodos de iteración es que el compilador genera una máquina de estado bastante grande y compleja para gestionar la ejecución diferida del código dentro del método de iteración. Esto generalmente genera una clase o dos. Estas clases están destinadas a tratar el caso general y no su caso específico, por lo que es probable que haya al menos un código que nunca se use. Puede ver lo que se genera mirando su ensamblaje con herramientas como ILSpy, JustDecompile o Reflector. Mostrará las clases en su ensamblado generadas por el compilador C # (generalmente nombres de clase que contienen ''<'', etc.)
Lo que el perfilador conoce es cómo el PDB se asocia a su código y, a pesar de la posibilidad de que todo el código que escribió posiblemente se esté ejecutando, aún existe la posibilidad de que no se haya ejecutado todo el código generado por el compilador. El generador de perfiles probablemente no lo sepa y simplemente dice que se ejecutó un determinado porcentaje (menos de 100) de un método de iterador en particular.
Una de las cosas que probablemente se generen es el código de manejo de excepciones. Debido a que el compilador no sabe que su código no generará o posiblemente no puede generar una excepción, generará código para compensar una excepción, necesita evitar que su estado se corrompa. Apuesto a que si incluyes una forma de lanzar una excepción en varios lugares en tu método de iteración basado en un indicador y ejecutas el método dos veces (una sin excepciones y otra con excepciones en la misma ejecución) los porcentajes serían diferentes, probablemente más altos porque el código de manejo de excepciones generado se ejercería entonces.
El hecho de que el final del método "parece" no ejecutarse es probable porque ese código es parte de un método diferente en la máquina de estados que se ejecuta y el compilador nunca genera una asociación desde el código generado al código en su clase .
ACTUALIZACIÓN: para obtener una mejor comprensión de lo que está haciendo el compilador y ver un ejemplo del tipo de código que genera, consulte la sección 10.14 Iteradores en la especificación C # ( http://www.microsoft.com/en-us/download/details) .aspx? id = 7029 )
Estoy usando dotCover para analizar la cobertura del código de mis pruebas unitarias, y obtengo algunos resultados extraños ... Tengo un método de iterador para el cual la cobertura no está completa, pero las declaraciones que no están cubiertas son solo las llaves de cierre al final del método.
Este es el método que estoy probando:
public static IEnumerable<T> CommonPrefix<T>(
this IEnumerable<T> source,
IEnumerable<T> other,
IEqualityComparer<T> comparer)
{
source.CheckArgumentNull("source");
other.CheckArgumentNull("other");
return source.CommonPrefixImpl(other, comparer);
}
private static IEnumerable<T> CommonPrefixImpl<T>(
this IEnumerable<T> source,
IEnumerable<T> other,
IEqualityComparer<T> comparer)
{
comparer = comparer ?? EqualityComparer<T>.Default;
using (IEnumerator<T> en1 = source.GetEnumerator(),
en2 = other.GetEnumerator())
{
while (en1.MoveNext() && en2.MoveNext())
{
if (comparer.Equals(en1.Current, en2.Current))
yield return en1.Current;
else
yield break;
}
} // not covered
} // not covered
La prueba unitaria:
[Test]
public void Test_CommonPrefix_SpecificComparer()
{
var first = new[] { "Foo", "Bar", "Baz", "Titi", "Tata", "Toto" };
var second = new[] { "FOO", "bAR", "baz", "tata", "Toto" };
var expected = new[] { "Foo", "Bar", "Baz" };
var actual = first.CommonPrefix(second, StringComparer.CurrentCultureIgnoreCase);
Assert.That(actual, Is.EquivalentTo(expected));
}
Y los resultados de cobertura:
Supongo que la llave de cierre del bloque de using
es en realidad las llamadas a Dispose
en los enumeradores; pero entonces, ¿por qué no se ejecuta? Primero sospeché que NUnit no estaba eliminando a los enumeradores, pero obtengo el mismo resultado si hago un foreach en actual
.
En cuanto a la segunda llave de cierre descubierta, no tengo idea de qué significa ... Supongo que está relacionada con la forma en que el compilador transforma el bloque de iteradores.
¿Puede alguien arrojar algo de luz sobre lo que son estas dos "declaraciones", y por qué no se ejecutan?
EDITAR: Peter planteó una muy buena pregunta: los resultados que se muestran arriba se obtuvieron al ejecutar las pruebas en una compilación de depuración . Si ejecuto las pruebas en una compilación de lanzamiento , la cobertura del método CommonPrefixImpl
es del 100%, por lo que probablemente esté relacionado con las optimizaciones del compilador.