7

ASP.NET 4.0 网络表单项目。我的代码隐藏中有以下内容。

public partial class _Default : System.Web.UI.Page
{
    private string testVar;

    protected override void OnInit(EventArgs e)
    {
        string testVar = "test";
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        var whatsTheValue = testVar;
    }
}

我在每个方法中设置了一个断点。当局部变量 ,testVar设置在 中时OnInit,如果我快速查看实例变量,它也有值“test”。当我玩到 时Page_Load,实例变量的值为null

我偶然遇到了这个,但这种行为让我感到困惑。我真的很惊讶它可以编译。我本来希望看到一些关于有两个同名变量的警告。话虽如此,让我更加困惑的是,实例变量在 OnInit 中获取了赋值,但在退出该方法时立即丢失了它。

有人可以向我解释这种行为吗?

4

3 回答 3

16

BrokenGlass 的回答当然是正确的;你一开始并没有看这个领域。当地人隐藏领域。

但是,我注意到没有人解决您问题的这一部分:

我真的很惊讶它可以编译。我本来希望看到一些关于有两个同名变量的警告。

在这种情况下,C# 编译器不会发出错误或警告,因为这样做会产生一种“脆弱的基类故障”形式。假设您有以下代码:

class B { }

class D : B 
{ 
    void M() 
    { 
        int x;
        ...

其中 B 由组织中的一个团队制作,D 由完全不同的团队制作。然后有一天 B 的维护者决定添加一个需要受保护字段的功能:

class B { protected int x; }

当你重新编译 D 时,它应该报错吗? 如果是这样,那么完全不同的团队中的某个人刚刚破坏了您的代码!C# 已经过精心设计,以最大限度地减少(尽管不是消除)这种破坏。

请注意,如果您在同一代码块中重新使用 x 来表示两个不同的事物,C#确实会出错。例如:

class B { protected int x; }
class D : B 
{ 
    void M() 
    { 
        x = 123; // meaning this.x inherited from B
        if (whatever)
        {
            int x = 10;
            ... 

这是非法的,因为现在在 M 的主体中,简单名称x用于表示this.x 局部变量x。因为这可能会令人困惑并且是一种糟糕的编程习惯,所以我们将其设为错误。但是,如果你真的想要,那么你可以通过确保用法在 *完全独立的块中来消除错误:

class B { protected int x; }
class D : B 
{ 
    void M() 
    { 
        {
            x = 123; // meaning this.x inherited from B
        }
        if (whatever)
        {
            int x = 10;

现在这些块不重叠,因此编译器假定您知道自己在做什么并允许代码编译。

于 2012-04-12T16:48:04.663 回答
8

如果我快速查看实例变量,它也有值“test”。当我玩到 Page_Load 时,实例变量的值为空。

没有看到实例变量,而是看到了局部变量。永远不会设置实例变量,因为局部作用域变量在其作用域生命周期内隐藏了实例变量。

从规范:

3.7.1 名称隐藏

实体的范围通常包含比实体的声明空间更多的程序文本。特别是,实体的范围可能包括引入新声明空间的声明,这些声明空间包含同名实体。这样的声明会导致原始实体被隐藏。相反,当实体没有隐藏时,它被称为可见。

当范围通过嵌套重叠以及范围通过继承重叠时,就会发生名称隐藏。这两种隐藏类型的特征将在以下部分中描述。

由于嵌套命名空间或命名空间内的类型、类或结构内的嵌套类型以及参数和局部变量声明的结果,可能会发生通过嵌套隐藏名称

于 2012-04-12T15:47:42.630 回答
0

'在每个方法中设置一个断点。在 OnInit 中设置局部变量 testVar 时,如果我快速查看实例变量,它也有值“test”。当我玩到 Page_Load 时,实例变量的值为空。

问题是VisualStudio的Watch基于断点提示时刻的变量命名。因此,当在方法内部遇到断点时OnInit,即使调试器显示实例变量具有值,这也是数据的错误可视化

所以一切都很好,只是数据的可视化是不正确的。

于 2012-04-12T15:49:44.500 回答