2010-02-04 8 views
14

¿Es equivalente?Usando vs lambda

 public static void Using<T>(this T disposable, Action<T> action) 
      where T:IDisposable 
     { 
      try { 
       action(disposable); 
      } 
      finally { 
       disposable.Dispose(); 
      } 
     } 

     new SqlConnection("").Using(conn => { 

     }); 

     using(var conn = new SqlConnection("")){ 

     }; 

en otras palabras, ¿podemos reemplazar el uso de la palabra clave con este método?

+5

Es posible que también desee consultar este artículo: http://marcgravell.blogspot.com/2009/11/selectmany-combining-disponible-y.html por Marc Gravell. –

+3

Pregunta honesta: ¿Por qué querrías? – Justin

+1

Navaja de Occam. – dotneter

Respuesta

19

no creo que esto es una idea especialmente buena, ya que también nos permitirá escribir

var conn = new SqlConnecction(""); 
conn.Using(c => /* do something with c */); 
conn.Open(); 

Este compile, pero al llegar a la última línea, se generará un ObjectDisposedException.

En cualquier caso, la expresión de codificación using es bien conocida, entonces ¿por qué es más difícil para tus compañeros desarrolladores leer tu código?

+11

Eso también puede ocurrir con una declaración '' using' "clásica:' var conn = ...; usando (conn) {...}; conn.Open(); ' – Heinzi

+0

Considero este reemplazo solo en teoría, como el uso del principio de la navaja de Occam. – dotneter

+3

@Heinzi Es por eso que hacemos cumplir en nuestros estándares de codificación que el objeto en una cláusula using también se define en la cláusula using, es decir 'using (IDbConnection con = ...) {...}' –

2

Una limitación: no puede acceder a los parámetros del método contenedor en su lambda.

2

La instrucción using comprueba si disposable es . Aparte de eso, en tiempo de ejecución obtendrás básicamente el mismo comportamiento (que no sea el stack frame adicional, y la llamada de delegado).

1

Como dijo Richard, hay una llamada de método extra entre la creación del objeto desechable y el inicio del intento. Esto aumenta el marco de tiempo en el que puede tener lugar una excepción asincrónica, lo que conduce a que no se elimine su objeto desechable. Sin embargo, esto no es un gran problema, porque los tipos que implementan IDisposable no deben adquirir sus recursos en el constructor (SqlConnection adquiere sus recursos durante la llamada al método Open()).

Así que, aunque su nueva forma de escribir la declaración de uso funcionaría, hace que leer para otros desarrolladores sea mucho más difícil y podría ser fácilmente abusado de la forma en que Mark Seemann señala.

¿Puede reemplazar la palabra clave using con su método de extensión Using? Sí. ¿Deberías hacerlo? No.

2

Algunas razones por las que prefiero no usar esto.

tiempo de compilación a prueba de mal

using (var foo=new Bar()) 
{ 
    foo=new Bar();// throws an error at compile time 
} 

Las estructuras de aplicación IDisposable

estructuras interfaces de aplicación están en caja cuando un método de interfaz se invoca en ellos. La instrucción using es lo suficientemente inteligente como para reconocer cuándo su destino es una estructura en tiempo de compilación y renuncia al boxeo.

+1

Técnicamente, el bit sobre las estructuras es en realidad un error del compilador. La especificación dice que hacer la conversión de boxeo; la implementación no lo hace; simplemente llama a Dispose() directamente. Podría decirse que esto es lo más "correcto" de todos modos; si el triturador muta la estructura, entonces probablemente debería estar mutando el original, no una copia en caja. –

+0

No es un error, es una característica de futuras versiones de CLR;); –

10

Observo que su método no hace todo que hace una instrucción "using". Por ejemplo, no introduce un nuevo espacio de declaración de variable local en el que se puede declarar una variable que se mantiene en el recurso.

Tampoco permite declarar todos los recursos desechables múltiples del mismo tipo de una sola vez.

Y, por último, no parece ser especialmente elegante consigo mismo.Una de las cosas buenas sobre el "uso" como una declaración es que se puede decir:

using(something) 
using(someotherthing) 
using(somethirdthing) 
{ 
    use all three, they'll all get disposed 
} 

¿Cómo se vería eso en su propuesta?

something.Using(
x=>someotherthing.Using(
y=>somethirdthing.Using(
z=> { use all three }))); 

Un poco bruto, francamente.

0

Es casi funcionalmente equivalente, pero en la práctica no proporciona ningún beneficio. La semántica de la declaración "tradicional" using es bien conocida y estándar. Si bien su enfoque puede comportarse de la misma manera (aunque existen algunas diferencias), introduce una sobrecarga y una complejidad innecesarias: no solo tiene invocaciones de métodos adicionales sino que también está replicando el código que el compilador generará automáticamente.

0

No. Está degradando una palabra clave de idioma [lo que significa que el compilador puede hacer algo a su alrededor, como señala Florian] a una llamada a método normal.

Aunque semánticamente pueden ser los mismos, el compilador no sabrá qué hará el método. Las comprobaciones de tiempo de compilación son mejores que las excepciones de tiempo de ejecución, como todos sabemos.