4

如果我使用 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。但是,如果我将声明更改fsSystem.IO.FileStream fs = null它就可以了。

为什么我需要显式设置fs为null?我也尝试fs在 try 块中声明,但随后The name fs does not exsist in the current context在 finally 块中出现错误。

顺便说一句:我知道我可以使用 Using 块,但我的问题的重点是了解 try/catch/finally 块的正确用法。

4

6 回答 6

5

赋值 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();
        }
    }
于 2010-07-21T20:45:22.520 回答
4

请参阅规范的第 5.3 节。

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

在函数成员的可执行代码中的给定位置,如果编译器可以通过静态流分析证明该变量已自动初始化或已成为至少一次赋值的目标,则称该变量已被确定赋值。

使用您的 try/catch/finally,try当您尝试访问块中的对象时,无法保证块的分配finallynull如您所见,您可以通过为变量(在本例中为 )分配初始值来满足要求。

于 2010-07-21T20:52:10.530 回答
3

C# 设计团队认为确保显式初始化事物是一个好主意。我倾向于同意;我已经被 C++ 中未初始化变量的错误所困扰。

于 2010-07-21T20:47:42.267 回答
2

初始化fsnull正确用法。编译器希望确保您只读取已初始化的变量,以避免严重错误。它不能保证你的 try 块中的初始化曾经被执行过

于 2010-07-21T20:48:21.593 回答
1

我内心的纯粹主义者会想做这样的事情:

    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
}
于 2010-07-21T22:29:27.917 回答
0

你很亲密。我将声明设置为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语句时这是可以接受的。

于 2010-07-21T20:45:02.147 回答