7

ASP.NET 4.0 Web フォーム プロジェクト。コードビハインドには次のものがあります。

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です。

偶然これに出くわしましたが、動作がわかりにくいです。私は実際にそれがコンパイルされることに驚いています。同じ名前の 2 つの変数があることについて、何らかの警告が表示されることを期待していました。そうは言っても、インスタンス変数が OnInit で割り当てを取得し、そのメソッドが終了するとすぐにそれを失うことは、私にとってさらに混乱を招きます。

誰かが私にこの振る舞いを説明できますか?

4

3 に答える 3

16

もちろん、BrokenGlass の答えは正しいです。あなたはそもそもフィールドを見ていません。ローカルはフィールドを非表示にします。

ただし、あなたの質問のこの部分に誰も対処していないことに注意してください。

私は実際にそれがコンパイルされることに驚いています。同じ名前の 2 つの変数があることについて、何らかの警告が表示されることを期待していました。

その場合、C# コンパイラはエラーや警告を発行しません。これを行うと、"脆弱な基本クラスの障害" の形式が作成されるためです。次のコードがあるとします。

class B { }

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

ここで、B は組織内の 1 つのチームによって作成され、D はまったく別のチームによって作成されます。その後、ある日、B のメンテナーは、保護されたフィールドを必要とする機能を追加することを決定します。

class B { protected int x; }

D を再コンパイルすると、エラーが発生しますか? もしそうなら、まったく別のチームの誰かがあなたのコードを壊しただけです! C# は、この種の破損を最小限に抑える (なくすわけではありません) ように慎重に設計されています。

同じコード ブロック内の2 つの異なるものを意味するために 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 の本体では、単純な名前がlocal variable の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 までプレイすると、インスタンス変数の値が null になります。

インスタンス変数は表示されません。ローカル変数が表示されますローカルにスコープされた変数は、スコープの有効期間中にインスタンス変数を隠しているため、インスタンス変数は設定されません。

仕様から:

3.7.1 名前の隠蔽

通常、エンティティのスコープには、エンティティの宣言スペースよりも多くのプログラム テキストが含まれます。特に、エンティティのスコープには、同じ名前のエンティティを含む新しい宣言スペースを導入する宣言が含まれる場合があります。このような宣言により、元のエンティティが非表示になります。逆に、エンティティは、隠されていなければ見えると言われます。

名前の隠蔽は、ネストによってスコープが重複する場合、および継承によってスコープが重複する場合に発生します。2 種類の非表示の特性については、次のセクションで説明します。

入れ子による名前の隠蔽は、名前空間内で名前空間または型を入れ子にした結果、クラスまたは構造体内で型を入れ子にした結果、およびパラメーターとローカル変数の宣言の結果として発生する可能性があります。

于 2012-04-12T15:47:42.630 に答える
0

各メソッド内にブレークポイントを設定しています。ローカル変数 testVar が OnInit に設定されている場合、インスタンス変数をざっと見てみると、値も「test」になっています。Page_Load までプレイすると、インスタンス変数の値が null になります。

事は、ブレークポイントのヒントの瞬間に変数の名前付けに基づいて VisualStudio の Watch ということです。そのため、メソッド内でブレークポイントにヒットしたOnInit場合、デバッガーがインスタンス変数に値があることを示していても、これはデータの間違った視覚化です。

したがって、すべて問題ありません。データの視覚化だけが正しくありません。

于 2012-04-12T15:49:44.500 に答える