c# - remarks - Si la declaración se evalúa como falsa, pero se ramifica como si fuera verdadera
remarks c# (1)
Vaya, depuración asincrónica.
Solo encontré una forma de hacerlo de manera efectiva. Utilice el rastreo (ojalá sea algo decente, tal vez log4net). Asegúrese de imprimir timestamp y threadId en cada línea. (también admite la sincronización de salida por llamada para rastrear la biblioteca para cuando la necesite, que no tiene que estar encendida todo el tiempo)
Eso es todo realmente.
Nota: Simplemente escribir en un archivo o stdout funciona para un primer sonrojo, pero si comienza a usarlo más, obtenga una biblioteca.
Estoy bastante perplejo. En un método asíncrono, tengo algunas declaraciones de guardia iniciales, que arrojan excepciones si se cumplen condiciones específicas.
Uno de ellos es el siguiente:
var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
Se supone que esto garantiza que haya páginas en el diccionario _transactionPages
y throw si no hay ninguna.
Esto es lo que sucede cuando lo ejecuto (lanzamiento y depuración compilación, depurador adjunto):
Entonces, el número de páginas en el diccionario es 3.
Y así, como se esperaba, la instrucción if que compara 3 a 0 se evalúa como falsa.
Pero luego, al avanzar más:
Entra en la rama como si la sentencia if se evalúa como verdadera y arroja la excepción.
¿Que me estoy perdiendo aqui?
ACTUALIZAR
Cuando hago esto:
private static readonly object _globalLock = new object();
public async Task<Checkpoint> CommitAsync(PageNumber dataRoot, PageNumber firstUnusedPage)
{
lock (_globalLock)
{
if (IsCompleted)
throw new InvalidOperationException(string.Format("Cannot commit completed transaction {0}", _txId));
var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
}
la instrucción if no se bifurca para lanzar la excepción. Este es el caso tanto para la depuración como para la versión de lanzamiento. ¿Algo está arruinando la pila de llamadas? Además, si en lugar del bloqueo agrego System.Threading.Thread.MemoryBarrier();
después de la declaración if
, no entrará en la rama.
ACTUALIZACIÓN 2
El misterio se vuelve un poco más grande. Es casi como si se usaran las reglas de scoping de C ++: D El siguiente código ( en la construcción de depuración ) mostrará el comportamiento esperado: no entrar en la rama y no lanzar. En la compilación de lanzamiento , irá a la rama y lanzará igual que antes.
private static readonly object _globalLock = new object();
public async Task<Checkpoint> CommitAsync(PageNumber dataRoot, PageNumber firstUnusedPage)
{
//lock (_globalLock)
{
if (IsCompleted)
throw new InvalidOperationException(string.Format("Cannot commit completed transaction {0}", _txId));
var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
}
Si hago un comentario sobre las "llaves de delimitación" irá a la rama y lanzará la excepción (como en mis imágenes originales).
¿FINAL? ACTUALIZAR
Bueno, eso es una mierda Hice algunos cambios en áreas de código no relacionadas y ahora ya no puedo reproducir el problema.