c# - 真正發生的事情在嘗試{return x; } finally {x = null; }聲明?



2 Answers

finally語句被執行,但返回值不受影響。 執行順序是:

  1. 執行返回語句之前的代碼
  2. 評估返回語句中的表達式
  3. 最後塊被執行
  4. 返回步驟2中評估的結果

這是一個簡短的程序來演示:

using System;

class Test
{
    static string x;

    static void Main()
    {
        Console.WriteLine(Method());
        Console.WriteLine(x);
    }

    static string Method()
    {
        try
        {
            x = "try";
            return x;
        }
        finally
        {
            x = "finally";
        }
    }
}

這將打印“嘗試”(因為這是返回的),然後“最終”,因為這是x的新值。

當然,如果我們要返回一個可變對象的引用(例如一個StringBuilder),那麼在finally塊中對對象所做的任何更改都將在返回時可見 - 這不會影響返回值本身(這只是一個參考)。

c# .net exception-handling

我在另一個問題中看到了這個提示,並想知道如果有人能向我解釋這個工作如何?

try { return x; } finally { x = null; }

我的意思是, finally語句是否真的 return語句之後執行? 這個代碼如何線程不安全? 你能想到任何額外的hackery可以做到這一點try-finally破解?




添加到由Marc Gravell和Jon Skeet給出的答案中,注意對象和其他參考類型在返回時的行為類似,但確實有一些差異很重要。

返回的“什麼”遵循與簡單類型相同的邏輯:

class Test {
    public static Exception AnException() {
        Exception ex = new Exception("Me");
        try {
            return ex;
        } finally {
            // Reference unchanged, Local variable changed
            ex = new Exception("Not Me");
        }
    }
}

在本地變量在finally塊中被分配一個新的引用之前,已經評估過返回的引用。

執行主要是:

class Test {
    public static Exception AnException() {
        Exception ex = new Exception("Me");
        Exception CS$1$0000 = null;
        try {
            CS$1$0000 = ex;
        } finally {
            // Reference unchanged, Local variable changed
            ex = new Exception("Not Me");
        }
        return CS$1$0000;
    }
}

不同之處在於,如果您不小心,可以使用對象的屬性/方法修改可變類型,這可能會導致意外的行為。

class Test2 {
    public static System.IO.MemoryStream BadStream(byte[] buffer) {
        System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer);
        try {
            return ms;
        } finally {
            // Reference unchanged, Referenced Object changed
            ms.Dispose();
        }
    }
}

關於try-return-finally的第二件事情是,返回後仍然可以修改通過引用傳遞的參數。 只有返回值已被評估並存儲在一個等待返回的臨時變量中,其他變量仍以正常方式修改。 out參數的合約甚至可能未完成,直到最終阻止這種方式。

class ByRefTests {
    public static int One(out int i) {
        try {
            i = 1;
            return i;
        } finally {
            // Return value unchanged, Store new value referenced variable
            i = 1000;
        }
    }

    public static int Two(ref int i) {
        try {
            i = 2;
            return i;
        } finally {
            // Return value unchanged, Store new value referenced variable
            i = 2000;
        }
    }

    public static int Three(out int i) {
        try {
            return 3;
        } finally {
            // This is not a compile error!
            // Return value unchanged, Store new value referenced variable
            i = 3000;
        }
    }
}

像其他任何流程構造一樣,“try-return-finally”也有其自己的位置,並且可以允許使用更清晰的代碼,而不是編寫它實際編譯的結構。 但必須小心使用,以避免陷入困境。




Related