在finally之前返回语句

本文关键字:返回 语句 finally | 更新日期: 2023-09-27 18:13:11

我有一个c#程序作为客户端和许多客户端程序,这是一个c# windows应用程序连接到这个c#服务器程序从sqlite数据库读取数据。为了避免在连接多个客户端时出现锁问题,我使用了下面的代码

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);
}

服务器挂起,需要重新启动服务器程序。在finally之前执行return语句是个好习惯吗?

的问候sangeetha

在finally之前返回语句

From MSDN

通过使用finally块,您可以清理在try块中分配的任何资源,并且即使在try块中发生异常也可以运行代码。通常,finally块的语句在控制离开try语句时运行。控制的转移可以发生在下列情况:正常执行,执行break、continue、goto或return语句,或在try语句之外传播异常。

在处理过的异常中,关联的finally块保证被运行。但是,如果未处理异常,则finally块的执行取决于异常展开操作的触发方式。这反过来又取决于你的电脑是如何设置的。有关更多信息,请参见CLR中的未处理异常处理。

是的,这就是finally语句的作用。它将在return之后执行,即使发生异常

编辑:这段简单的代码将向您展示,catch块并不需要执行finally块

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

由于没有catch块,因此不能保证finally将被执行。来自MSDN - try-finally (c#参考)和"锁和异常不能混合"(Eric Lippert)

在处理过的异常中,关联的finally块得到保证待运行。但是,如果异常未处理,则执行最后,块取决于异常展开操作的方式。而这又取决于你的电脑是如何设置的。

并且从随后提到的链接(CLR中未处理的异常处理)中有各种考虑因素,这可能意味着您最终会终止线程。但是,我不知道这是否会给锁对象留下一个锁。

如果你想确保:

  • 你释放锁;但
  • 你不希望在这个级别处理异常,相反,你希望它由更高级别的异常处理程序处理

那么做:

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;
}

但是,请注意:不要使用catch (Exception)来隐藏异常,这只有在你重新抛出异常时才可以。人们还建议您使用单个return语句,通常这将在您的try块之外。

编辑:

通过测试程序确认,来自MSDN -托管线程中的异常

从。net Framework 2.0版本开始,通用语言运行时允许线程中大多数未处理的异常继续进行自然。在大多数情况下,这意味着未处理的异常导致应用程序终止。

所以,如果你不处理你的异常,你的应用程序将崩溃(你不必担心锁)。如果你确实处理了它,那么你的原始代码将执行它最终阻塞,你就可以了。

编辑2:测试代码更新,因为它没有正确地说明非触发最后:

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);
        }
    }
}

从try catch finally块内返回是不好的做法吗?
这是在c#中编写异常处理的正确方式,并且总是finally块将被执行,它不依赖于返回的位置。我不知道你的代码,但你应该在其他地方找到你的问题(例如,如果你的代码托管在IIS中,我会怀疑锁对象在不同加载域的状态,或者可能锁只是一个传入调用,它发生在数据库中,或者什么是Request.Clear()你没有锁块?)。您可以很容易地记录来电状态并找到问题。