在C#和Java语言中(可能还有其他语言),在"try“块中声明的变量不在相应的"catch”或"finally“块的作用域中。例如,以下代码无法编译:
try {
String s = "test";
// (more code...)
}
catch {
Console.Out.WriteLine(s); //Java fans: think "System.out.println" here instead
}
在此代码中,catch块中对s的引用发生编译时错误,因为s仅在try块的作用域中。(在Java语言中,编译错误是“无法解析”;在C#中,错误是“名称"s”在当前上下文中不存在“)。
这个问题的一般解决方案似乎是在try块之前声明变量,而不是在try块内:
String s;
try {
s = "test";
// (more code...)
}
catch {
Console.Out.WriteLine(s); //Java fans: think "System.out.println" here instead
}
然而,至少对我来说,(1)这感觉像是一个笨拙的解决方案,(2)它导致变量的作用域比程序员预期的更大(整个方法的其余部分,而不仅仅是try-catch-finally的上下文)。
我的问题是,这个语言设计决策背后的理由是什么(在Java、C#和/或任何其他适用的语言中)?
发布于 2008-09-18 17:58:40
您如何确定已到达catch块中的声明部分?如果实例化抛出异常怎么办?
发布于 2008-09-18 21:48:08
其他每个人都提出了基础知识--块中发生的事情将保留在块中。但在.NET的情况下,检查编译器认为正在发生的事情可能会有所帮助。例如,以下面的try/catch代码为例(请注意,StreamReader是在块之外正确声明的):
static void TryCatchFinally()
{
StreamReader sr = null;
try
{
sr = new StreamReader(path);
Console.WriteLine(sr.ReadToEnd());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
if (sr != null)
{
sr.Close();
}
}
}
这将在MSIL中编译为类似于以下内容:
.method private hidebysig static void TryCatchFinallyDispose() cil managed
{
// Code size 53 (0x35)
.maxstack 2
.locals init ([0] class [mscorlib]System.IO.StreamReader sr,
[1] class [mscorlib]System.Exception ex)
IL_0000: ldnull
IL_0001: stloc.0
.try
{
.try
{
IL_0002: ldsfld string UsingTest.Class1::path
IL_0007: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(string)
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: callvirt instance string [mscorlib]System.IO.TextReader::ReadToEnd()
IL_0013: call void [mscorlib]System.Console::WriteLine(string)
IL_0018: leave.s IL_0028
} // end .try
catch [mscorlib]System.Exception
{
IL_001a: stloc.1
IL_001b: ldloc.1
IL_001c: callvirt instance string [mscorlib]System.Exception::ToString()
IL_0021: call void [mscorlib]System.Console::WriteLine(string)
IL_0026: leave.s IL_0028
} // end handler
IL_0028: leave.s IL_0034
} // end .try
finally
{
IL_002a: ldloc.0
IL_002b: brfalse.s IL_0033
IL_002d: ldloc.0
IL_002e: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0033: endfinally
} // end handler
IL_0034: ret
} // end of method Class1::TryCatchFinallyDispose
我们看到了什么?MSIL尊重这些块--它们本质上是编译C#时生成的底层代码的一部分。作用域不仅在C#规范中是硬设置的,在CLR和CLS规范中也是如此。
作用域可以保护您,但您有时确实需要绕过它。随着时间的推移,你习惯了它,它开始感觉很自然。就像其他人所说的,在一个区块中发生的事情只会在那个区块中发生。你想分享些什么吗?你得走出街区。
发布于 2008-09-18 17:59:19
无论如何,在C++中,自动变量的作用域受到它周围的大括号的限制。为什么有人会期望在花括号外插入try关键字会有所不同呢?
https://stackoverflow.com/questions/94977
复制相似问题