pattern net example disposing asp c#

c# - net - Si mi estructura se implementa como IDisposable, ¿se encajonará cuando se utilice en una declaración de uso?



protected override void dispose (4)

Este es un duplicado de ¿ Cuándo un argumento de uso usa su argumento, cuando es una estructura?

ACTUALIZACIÓN: Esta pregunta fue el tema de mi blog en marzo de 2011 . Gracias por la gran pregunta.

Algunos puntos:

  • Como otros han señalado correctamente, un tipo de valor que implementa IDisposable no está encuadrado cuando se dispone como consecuencia de que el control deje una declaración de uso.
  • Esto es técnicamente una violación de la especificación de C #. La especificación establece que el bloque finally debe tener la semántica de ((IDisposable)resource).Dispose(); que es claramente una conversión de boxeo. En realidad no generamos la conversión de boxeo. Como la mayoría de las veces esto es lo que quieres, no estamos perdiendo el sueño por eso.
  • Un tipo de valor desechable parece una idea potencialmente mala. Es demasiado fácil hacer una copia accidental de un tipo de valor; son copiados por valor después de todo.
  • ¿Por qué diablos te importa si esto encaja o no? Espero que no esté preguntando esto porque quiere que el método de eliminación mute la variable que contiene el tipo de valor. Esa sería una mala idea por cierto. Los tipos de valores mutables son malos.

Si mi estructura se implementa como IDisposable, ¿se encajonará cuando se utilice en una declaración de uso?

Gracias

Editar: este bloqueo de tiempo es una estructura e implementa Idisposable. http://www.interact-sw.co.uk/iangblog/2004/04/26/yetmoretimedlocking

Edición 2: mirando el IL parece que si su estructura expone a Dispose () como público, el compilador llama a Desechar cuando una instancia de la estructura queda fuera del alcance si olvida llamar a Dispose () (por ejemplo, no está usando el "utilizando" declaración)?


Esto no encajonará (me sorprendió). Creo que la explicación de bnkdev lo cubre. Así es como lo probé:

Escribí la aplicación de la consola rápida a continuación (nota, incluí BoxTest (), que que encajará, de modo que tenga algo con qué comparar).

Luego usé Reflector para desensamblar la salida compilada a IL (podría usar ILDASM).

namespace StructInterfaceBoxingTest { public struct TestStruct : IDisposable { #region IDisposable Members public void Dispose() { System.Console.WriteLine("Boo!"); } #endregion } class Program { static void Main(string[] args) { using (TestStruct str = new TestStruct()) { } } static void BoxTest() { TestStruct str = new TestStruct(); ThisWillBox(str); } static void ThisWillBox(object item) {} } }

Ok, primero, aquí está el IL para BoxTest - note la instrucción de la caja en la línea L_000a (énfasis de astersik)

.method private hidebysig static void BoxTest() cil managed { .maxstack 1 .locals init ( [0] valuetype StructInterfaceBoxingTest.TestStruct str) L_0000: nop L_0001: ldloca.s str L_0003: initobj StructInterfaceBoxingTest.TestStruct L_0009: ldloc.0 L_000a: **box** StructInterfaceBoxingTest.TestStruct L_000f: call void StructInterfaceBoxingTest.Program::ThisWillBox(object) L_0014: nop L_0015: ret }

Ahora eche un vistazo a Main (donde usamos una declaración de uso con nuestra estructura IDisposable):

.method private hidebysig static void Main(string[] args) cil managed { .entrypoint .maxstack 1 .locals init ( [0] valuetype StructInterfaceBoxingTest.TestStruct str) L_0000: nop L_0001: ldloca.s str L_0003: initobj StructInterfaceBoxingTest.TestStruct L_0009: nop L_000a: nop L_000b: leave.s L_001c L_000d: ldloca.s str L_000f: constrained StructInterfaceBoxingTest.TestStruct L_0015: callvirt instance void [mscorlib]System.IDisposable::Dispose() L_001a: nop L_001b: endfinally L_001c: nop L_001d: ret .try L_0009 to L_000d finally handler L_000d to L_001c }

Tenga en cuenta la palabra clave restringida en la línea L_000f. No puedo encontrar una referencia para lo que significa exactamente esa palabra clave, pero si lees la publicación de bnkdev, creo que esta es la llamada virtual restringida que está describiendo.


Por Eric Lippert :

Una llamada a IDisposable.Dispose en una estructura se genera como una llamada virtual restringida, que la mayoría de las veces NO encierra el valor.

Una llamada virtual restringida en un tipo de valor solo encierra el valor si el método NO es implementado por el tipo. Las únicas circunstancias en las que un método virtual no puede ser implementado por el tipo de valor es cuando el método es, por ejemplo, ToString, e implementado por la clase base, System.ValueType.

Consulte la sección 2.1 de la Partición III de la documentación de la CLI para obtener más detalles.


No, no se enjaula.

using no es una llamada de método. Es el azúcar sintáctico que el compilador simplemente convierte, de forma áspera, esto:

MyClass m = new MyClass() try { // ... } finally { if (m != null) { m.Dispose(); } }

Nunca usa IDisposable en la declaración y nunca pasa la instancia a otra cosa. Para una estructura, el compilador genera algo aún más pequeño:

MyStruct m = new MyStruct() try { // ... } finally { m.Dispose(); }

Dado que una estructura no puede ser nula.

Ahora, para estar 100% seguro de que nunca encaja, mira el IL.

Pruebe este código de ejemplo:

class StructBox { public static void Test() { using(MyStruct m = new MyStruct()) { } MyStruct m2 = new MyStruct(); DisposeSomething(m2); } public static void DisposeSomething(IDisposable disposable) { if (disposable != null) { disposable.Dispose(); } } private struct MyStruct : IDisposable { public void Dispose() { // just kidding } } }

Entonces mira el IL:

.method public hidebysig static void Test() cil managed { .maxstack 1 .locals init ( [0] valuetype ConsoleApplication1.StructBox/MyStruct m, [1] valuetype ConsoleApplication1.StructBox/MyStruct m2) L_0000: ldloca.s m L_0002: initobj ConsoleApplication1.StructBox/MyStruct L_0008: leave.s L_0018 L_000a: ldloca.s m L_000c: constrained ConsoleApplication1.StructBox/MyStruct L_0012: callvirt instance void [mscorlib]System.IDisposable::Dispose() L_0017: endfinally L_0018: ldloca.s m2 L_001a: initobj ConsoleApplication1.StructBox/MyStruct L_0020: ldloc.1 L_0021: box ConsoleApplication1.StructBox/MyStruct L_0026: call void ConsoleApplication1.StructBox::DisposeSomething(class [mscorlib]System.IDisposable) L_002b: ret .try L_0008 to L_000a finally handler L_000a to L_0018 }

Las líneas L_0000 a L_0017 representan la declaración m y el using . No hay boxeo.

Las líneas L_0018 a L_0026 representan la declaración de m2 y la llamada a DisposeSomething . Ver en la box L_0021.