2010-05-06 17 views
5

Tengo un poco de código con la siguiente lógica:¿Qué hacer cuando se usa Contract.Assert (true) y el método debe devolver algo?

//pseudo-code 
foreach (element in elementList) { 
    if (element is whatever) 
     return element; 
    } 
} 

En teoría, siempre hay un elemento que es lo que sea, por lo que este método debería plantear ningún problema. En cualquier caso, he puesto una afirmación sobre el final del método sólo para estar seguro:

//pseudo-code 
foreach (element in elementList) { 
    if (element is whatever) 
     return element; 
    } 
} 

Contract.Assert(false, "Invalid state!"); 

El problema es que a medida que este método tiene que devolver algo, y el compilador no entiende que la afirmación romperá la ejecución del programa. Antes de usar contratos, en este tipo de situaciones solía arrojar una excepción que resolvía el problema. ¿Cómo manejarías esto con Contract.Assert()? ¿Regresar nulo o por defecto (element_type) después de la llamada Contract.Assert() sabiendo que nunca se llamará y se cerrará el compilador? ¿O hay alguna otra manera más elegante de hacer esto?

Gracias

+0

No quiere decir 'Contract.Assert ("Estado inválido!" False);'? –

+0

Sí, lo hice. : facep: –

Respuesta

2

usted podría ir con

var result = null; 
foreach (element in elementList) { 
    if (element is whatever) 
     result = element; 
     break; 
    } 
} 

Contract.Assert(result != null, "Invalid state!"); 
return result; 

Se introduce una ruptura, pero que tiene un aspecto más limpio alrededor de la vuelta.

aún más limpio sería

return elementList.Where(e => e is whatever).First(); 

Editar como @devoured señaló lo anterior sería golpeado toda la lista

más limpio y sin el dónde

return elementList.First(e => e is whatever); 

final de edición

Eso simplemente explota si no se encuentra nada.

Pero si realmente quiere la aserción que podría ser

var results = elementList.Where(e => e is whatever); 
Contract.Assert(results.Count() == 1, "Boo"); 
return results.First(); 

pero que se repetirá toda la lista también.

+0

Acerca del primer uso de LINQ, ¿ejecutará todo el elementList o dejará de buscar más elementos en el momento en que encuentre el primero? –

+1

@devoured Creo que mientras escribía se ejecutará toda la lista. Pero tal vez usarlo como 'elementList.First (e => e es lo que sea)' (observe la falta de 'Donde') debe detenerse en el primero. Pero no lo he probado –

+0

Oooooooops.He perdido el botón "Aceptar botón de respuesta" y he votado negativamente. Tienes que editar tu respuesta para que pueda cambiar el voto :( –

1

Creo que sería mejor que con un Contract.Requires (es decir, una condición previa) que un Contract.Assert aquí. La condición previa para su fragmento es que elementList contiene al menos un elemento donde se cumple la condición.

Debería ser explícito al respecto en lugar de confiar en un Assert(false), que requiere que el lector entienda el resto de la función y siga el control de flujo para deducir las situaciones en las que se alcanza el Assert(false).

Por lo tanto, me gustaría volver a escribir como:

//precondition (checked only in debug builds) 
Contract.Require(elementList.Where(e => e is whatever).Count > 0,"elementList requires at least one element meeting condition whatever"); 
//do work (throws in release builds, never reached in debug ones) 
return elementList.First(e => e is whatever); 
+0

-, por lo que tendrá que iterar sobre la lista dos veces ... y eso no es lo mejor ... incluso está utilizando '.Count()> 0' (la llamada de propiedad no es posible ya que el retorno de' .Where() 'es' IEnumerable ', y ese tipo no tiene la propiedad' .Count' sino un método de extensión ... 'Enumerable.Count()' que necesita iterar sobre el resultado completo - más bien use '.Any()' –

+0

No. Alguien no entiende cómo funcionan los contratos. Cuando la velocidad es importante, mi respuesta itera sobre la lista como máximo una vez. La precondición hace que código más legible, ayuda a la depuración y sirve como una pista para el optimizador. No se ejecuta en el código de producción. –

+0

No. Alguien no entiende cómo funciona Linq (por favor, lea http://stackoverflow.com/questions/305092/which-method-performs-better-any-vs-count-0), y que la propiedad 'Count' no existe en un 'IEnumerable ' - sin embargo, la ejecución de 'Contract.Require' es una cuestión de configuración (también conocida como' Realizar verificación de contrato en tiempo de ejecución': ** 'Full' **,' Pre y Post', ...). –

Cuestiones relacionadas