Pregunta devolver declaración antes de finalmente


Tengo un programa c # que actúa como cliente y muchos programas cliente, que una vez más es una aplicación de Windows c # se conecta a este programa servidor c # para leer datos de la base de datos sqlite. Para evitar problemas de bloqueo al conectar varios clientes he utilizado el código siguiente,

System.Threading.Monitor.Enter(Lock);

try                       
{                     
    filter.Execute();//get data from database
    Request.Clear();
    return filter.XML;//create xml and return to client
}
finally
{
    System.Threading.Monitor.Exit(Lock);
}

el servidor se cuelga algunas veces y necesita reiniciar el programa del servidor. ¿Es una buena práctica hacer la declaración de devolución antes de finalmente?

Saludos Sangeetha


5
2018-05-11 10:21


origen


Respuestas:


De MSDN

Al usar un bloque finally, puede limpiar cualquier recurso que esté asignado en un bloque try, y puede ejecutar código incluso si ocurre una excepción en el bloque try. Normalmente, las declaraciones de un bloque finalmente se ejecutan cuando el control deja una declaración de prueba. La transferencia de control puede ocurrir como resultado de la ejecución normal, de la ejecución de una instrucción break, continue, goto o return, o de la propagación de una excepción fuera de la instrucción try.

Dentro de una excepción manejada, se garantiza que se ejecutará el bloque finally asociado. Sin embargo, si la excepción no se maneja, la ejecución del bloque finally depende de cómo se desencadena la operación de desenrollamiento de la excepción. Eso, a su vez, depende de cómo esté configurada su computadora. Para obtener más información, consulte Procesamiento de excepciones no manejadas en el CLR.


4
2018-05-11 10:27



Sí, es lo que finally declaración es para. Se ejecutará después del return, incluso si ocurre una excepción

EDITAR: Este simple código le mostrará que el bloque catch no es necesario para ejecutar finalmente el bloque.

public Form1()
{
    InitializeComponent();
    check();
}

private string check()
{
    try
    {
        return String.Empty;
    }
    finally
    {
        MessageBox.Show("finally");
    }
}

2
2018-05-11 10:25



Como no tiene un bloque catch, no hay garantía de que finalmente se ejecutará. De MSDN - try-finally (referencia C #) y "Cerraduras y excepciones no se mezclan" (Eric Lippert)

Dentro de una excepción manejada, el bloque finalmente asociado está garantizado.   para ejecutarse. Sin embargo, Si la excepción no se maneja, la ejecución de la   Finalmente, el bloque depende de cómo sea la excepción de operación de desenrollado.   disparado. Eso, a su vez, depende de cómo esté configurada su computadora.

Y desde el enlace que luego se menciona (Procesamiento de excepciones no manejadas en el CLR) hay varias consideraciones que pueden significar que terminas con un hilo terminado. Aunque honestamente no sé si eso te dejaría con un candado en el objeto de bloqueo.

Si quisieras asegurarte de que:

  • sueltas el candado; pero
  • no quiere manejar la excepción en este nivel, en lugar de eso quiere que sea manejado por un controlador de excepciones de nivel superior

Entonces hazlo:

TheXmlType xml = null;
Monitor.Enter(Lock);
bool inLock = true;
try {
  ...
  xml = filter.Xml; // put this here in case it throws an exception
  inLock = false; // set this here in case monitor.exit is to 
    // throw an exception so we don't do the same all over again in the catch block
  Monitor.Exit(Lock);
  return xml; // this is fine here, but i would normally put it outside my try
}
catch (Exception) {
  if (inLock) Monitor.Exit(Lock);
  throw;
}

Pero, tenga en cuenta: no use catch (Exception) para ocultar excepciones, esto solo está bien si está volviendo a lanzar la excepción. La gente también recomienda que tengas una sola return declaración, y por lo general esto sería fuera de su bloque de prueba.

EDITAR:

Confirmado con un programa de prueba, y desde MSDN: excepciones en hilos gestionados

Comenzando con .NET Framework versión 2.0, el lenguaje común   tiempo de ejecución permite que la mayoría de las excepciones no controladas en subprocesos procedan   naturalmente. En la mayoría de los casos, esto significa que la excepción no controlada   hace que la aplicación termine.

Entonces, si no maneja su excepción, su aplicación se bloqueará (y no tendrá que preocuparse por el bloqueo). Si lo manejas, entonces tu código original se ejecutará, finalmente se bloqueará y estarás bien.

EDICION 2: El código de prueba se actualizó porque no ilustraba correctamente el hecho de no disparar finalmente:

class Program
{ 
    static void Main(string[] args) {
        Program p =new Program();
        p.Start();
        Console.WriteLine("done, press enter to finish");
        Console.ReadLine();
    }

    private readonly object SyncRoot = new object();
    ManualResetEvent mre = new ManualResetEvent(false);

    private void Start() {
        /*
         * The application will run the thread, which throws an exception
         * While Windows kicks in to deal with it and terminate the app, we still get 
         * a couple of "Failed to lock" messages
         * */

        Thread t1 = new Thread(SetLockAndTerminate);
        t1.Start();
        mre.WaitOne();
        for (int i = 0; i < 10; i++) {
            if (!Monitor.TryEnter(this.SyncRoot, 1000)) {
                Console.WriteLine("Failed to lock");
            }
            else {
                Console.WriteLine("lock succeeded");
                return;
            }
        }
        Console.WriteLine("FINALLY NOT CALLED");
    }
    public int CauseAnOverflow(int i)
    {
        return CauseAnOverflow(i + 1);
    }
    public void SetLockAndTerminate() {
        Monitor.Enter(this.SyncRoot);
        Console.WriteLine("Entered");
        try {
            mre.Set();
            CauseAnOverflow(1); // Cause a stack overflow, prevents finally firing
        }
        finally {
            Console.WriteLine("Exiting");
            Monitor.Exit(this.SyncRoot);
        }
    }
}

1
2018-05-11 11:08



¿Es una mala práctica regresar desde dentro de un bloque try catch finally?
Es la forma correcta de escribir Exception Handling en c # y siempre se ejecutará el bloqueo, no depende del lugar de devolución. No sé sobre su código, pero debería encontrar su problema en otro lugar (por ejemplo, si su código se alojó en IIS, sospecho que el estado del objeto de bloqueo en diferentes dominios cargados o tal vez el bloqueo es solo para una llamada entrante y sucede en la base de datos o qué es Request.Clear () no tiene un bloqueo de bloqueo allí?). Puede registrar fácilmente el estado de las llamadas entrantes y encontrar el problema.


0
2018-05-11 17:12