作用域(scope), 定义空间(declaration space) 和 生存期(lifetime)
译自Eric Lippert's Blog, 原文: http://blogs.msdn.com/ericlippert/archive/2009/08/03/what-s-the-difference-part-two-scope-vs-declaration-space-vs-lifetime.aspx
在编程语言设计中,作用域(scope)通常是最容易混淆的概念。
人们似乎不经意间就使用这个概念,我经常看到它被当做生存期(lifetime)或定义空间(declaration space)使用,例如"当这个变量超出作用域时,对应的内存空间将被释放"。当然在非正式场合,只要听众能清楚地理解你所指的意思,使用"作用域"来表示是完全可以接受的。但是在更正式的场合,比如书中或语言标准中,就需要更精确地使用这些概念。
C#中作用域和定义空间的区别是微妙的。
一个命名实体(entity)的作用域是源代码中可以合法使用它的非限定名(unqualified name)来引用它的范围。
这里有些微妙的东西, 这个定义并没有别的隐含的意思 -- 它并非表示如果你可以合法使用一个实体的非限定名,则通过这个非限定名就可以引用这个实体。因为作用域是允许重叠(overlap)的。例如,如果有以下代码:
{
int x;
void M()
{
int x;
}
}
字段x(field)的作用域是源代码中类C(class)的整个定义部分,包括方法M(method)的整个定义;局部变量x(local variable)的作用域是方法M的主体部分。所以这两个实体的作用域有重叠的部分。当你在不同的位置使用非限定名"x",将得到不同的实体(字段x或者局部变量x)。
相反, 定义空间是一段其中不允许存在具有相同名称实体的源代码范围。例如,在类C的定义部分,除了方法M的主体部分,不允许别的实体也命名为x。一旦定义了个字段x, 就不能再定义别的称为x的字段,属性(property), 内嵌类型(nested type)或事件(event)。
正因为有重载机制(overload), 使得方法有一点特殊。可以特别定义有方法的定义空间为"一个类中所有具有相同名称的重载方法构成一个实体", 也可以重新定义定义空间为"定义空间中不允许存在具有相同名称的实体, 除了具有不同签名(signature)的方法"。
简短地说,作用域解决了“在哪里可以使用这个名称”的问题;命名空间解决了“这个名称在哪里是唯一的”的问题。
生存期和作用域经常在局部变量上容易混淆,因为在局部变量上这两者关系太复杂了。扼要地讲,就是只要当前的执行点(point of execution)在局部变量的作用域内,至少能保证它的内容可用。但也可能局部变量的内容在超出它的作用域外也是可用的,比如捕获变量(capture variable, variable capturing , 在匿名函数中使用外部变量 )将扩展这个变量的生存期。