簡體   English   中英

我應該如何初始化將在try / catch / finally塊中使用的變量?

[英]How should I initialize variables that will be used in a try/catch/finally block?

如果我使用try / catch / finally塊我應該在哪里以及如何初始化變量? 例如,假設我正在嘗試使用FileStream。 我想捕獲創建或使用流時拋出的任何異常。 然后,無論是否有任何問題,我都希望確保創建的任何流都已關閉。

所以我會做這樣的事情:

        System.IO.FileStream fs;
        try
        {
            fs = new System.IO.FileStream("C:\test.txt", System.IO.FileMode.Open);
            //do something with the file stream
        }
        catch (Exception exp)
        {
            //handle exceptions
        }
        finally
        {
            //ERROR: "unassigned local variable fs"
            if (fs != null)
            {
                fs.Close();
            }
        }

然而,這給了我一個錯誤,在finally塊中說unassigned local variable fs 但是,如果我將fs的聲明更改為System.IO.FileStream fs = null可以正常工作。

為什么我需要將fs顯式設置為null? 我也試過在try塊中聲明fs ,但后來我得到了錯誤The name fs does not exsist in the current context在finally塊The name fs does not exsist in the current contextThe name fs does not exsist in the current context

BTW:我知道我可以使用Using塊,但我的問題是要了解try / catch / finally塊的正確用法。

分配fs = null;

  System.IO.FileStream fs = null;
    try
    {
        fs = new System.IO.FileStream("C:\test.txt", System.IO.FileMode.Open);
        //do something with the file stream
    }
    catch (Exception exp)
    {
        //handle exceptions
    }
    finally
    {
        //ERROR: "unassigned local variable fs"
        if (fs != null)
        {
            fs.Close();
        }
    }

見規范5.3節。

http://msdn.microsoft.com/en-us/library/aa691172(VS.71).aspx

在函數成員的可執行代碼中的給定位置處,如果編譯器可以通過靜態流分析證明該變量已被自動初始化或已成為至少一個賦值的目標,則稱該變量是明確賦值的。

使用try / catch / finally,當您嘗試訪問finally塊中的對象時,無法保證try塊的分配。 如您所見,您可以通過為變量分配初始值來滿足要求(在本例中為null )。

C#設計團隊認為確保明確初始化事物是一個好主意。 我傾向於同意; 在C ++中,我已經被來自未初始化變量的錯誤所困擾。

fs初始化為null是正確的用法。 編譯器希望確保您只讀取初始化變量,以避免嚴重錯誤。 並且它無法保證您的try塊中的初始化將被執行

我的純粹主義者想要做這樣的事情:

    void DoSomethingWithStream()
    {
        try
        {
            System.IO.FileStream fs = new System.IO.FileStream(@"C:\test.txt", System.IO.FileMode.Open);
            try
            {
                // do something with the file stream

            }
            catch (Exception ex)
            {
                // handle exceptions caused by reading the stream,
                // if these need to be handled separately from exceptions caused by opening the stream
            }
            finally
            {
                // FileStream.Close might throw an exception, so put FileStream.Dispose in a separate try/finally
                fs.Dispose();
            }
        }
        catch (Exception ex)
        {
            // handle exceptions that were either thrown by opening the filestream, thrown by closing the filestream, or not caught by the inner try/catch
        }
    }

盡管如此,這將是一個混亂:

    void DoSomethingWithStream_PartDeux()
    {
        try
        {
            System.IO.FileStream fs = new System.IO.FileStream(@"C:\test.txt", System.IO.FileMode.Open);
            try
            {
                try
                {
                    // do something with the file stream

                }
                catch (Exception ex)
                {
                    // handle exceptions caused by reading the stream,
                    // if these need to be handled separately from exceptions caused by opening the stream
                }
                finally
                {
                    fs.Close();
                }
            }
            finally
            {
                // FileStream.Close might throw an exception, so put FileStream.Dispose in a separate try/finally
                fs.Dispose();
            }
        }
        catch (Exception ex)
        {
            // handle exceptions
        }
    }

訪問數據庫可能更糟糕:

    void DoSomethingWithDatabase()
    {
        var connection = new System.Data.SqlClient.SqlConnection("Connect to mah database!");
        try
        {
            var command = new System.Data.SqlClient.SqlCommand("Get mah data!", connection);

            connection.Open();
            try
            {
                var reader = command.ExecuteReader();
                try
                {
                    try
                    {
                        // read data from data reader (duh)
                    }
                    finally
                    {
                        reader.Close();
                    }
                }
                finally
                {
                    reader.Dispose();
                }
            }
            finally
            {
                connection.Close();
            }
        }
        finally
        {
            connection.Dispose();
        }
    }

但是,在大多數情況下,如果你要在之后立即處理它們(除非你真的是偏執狂),我真的不需要明確地關閉你的流/連接/數據讀取器。 所以,上面的數據庫代碼可以很容易:

    void DoSomethingWithDatabase_PartDeux()
    {
        using (var connection = new System.Data.SqlClient.SqlConnection("Connect to mah database!"))
        {
            var command = new System.Data.SqlClient.SqlCommand("Get mah data!", connection);

            connection.Open();
            using(var reader = command.ExecuteReader())
            {
                // read data from data reader (duh)
            }
        }
    }

也許我剛被Wily博士的邪惡API編碼所玷污。 使用initialize-variable-to-null技巧不適用於他的框架:

    void DoSomethingWithDrWilyEvilBoobyTrap()
    {
        Dr.Wily.Evil.BoobyTrap trap = null;
        try
        {
            trap = new Dr.Wily.Evil.BoobyTrap(Dr.Wily.Evil.Evilness.Very);

            // do something with booby trap
        }
        catch (Exception ex)
        {
            // handle exceptions
        }
        finally
        {
            if (trap != null) // Exception thrown here!
                trap.Dispose(); // Exception thrown here as well!
        }
    }

以下是他API中一些源代碼的預覽:

public enum Evilness
{
    Slight,
    Moderate,
    Very,
}

class BoobyTrap : IDisposable
{
    public Evilness Evil { get; protected set; }

    public BoobyTrap(Evilness evil)
    {
        this.Evil = evil;
    }

    public void DoEvil()
    {
        // ... snip (sorry, it's just too evil) ...
    }

    public static bool IsNull(BoobyTrap instance)
    {
        throw new Exception("I bet you thought this function would work, didn't you?  Well it doesn't!  You should know whether or not your variables are null.  Quit asking me!");
    }

    public static bool operator !=(BoobyTrap x, object y)
    {
        if(y == null)
            throw new Exception("You cannot check if an instance of a BoobyTrap is null using the != operator.  Mwahahaha!!!");

        return x.Equals(y);
    }

    public static bool operator ==(BoobyTrap x, object y)
    {
        if (y == null)
            throw new Exception("You cannot check if an instance of a BoobyTrap is null using the == operator.  Mwahahaha!!!");

        return x.Equals(y);
    }

    #region IDisposable Members

    public void Dispose()
    {
        switch (this.Evil)
        {
            case Evilness.Moderate:
            case Evilness.Very:
                throw new Exception("This object is cursed.  You may not dispose of it.");
        }
    }

    #endregion
}

你很親密 我將聲明設置為null

System.IO.FileStream fs = null;
try
{
    fs = new System.IO.FileStream("C:\test.txt", System.IO.FileMode.Open);
    //do something with the file stream
}
catch (Exception exp)
{
    //handle exceptions
}
finally
{
    //ERROR: "unassigned local variable fs"
    if (fs != null)
    {
        fs.Close();
    }
}

我認為當你不能使用using語句時,這是非常可以接受的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM