2

私は次のコードを持っています(以下のコードはプロパティを更新しないことに注意してください)

private void queryResultsFilePath_Click(object sender, EventArgs e)
{
        Library.SProc.Browse browser = new Browse();
        browser.selectFile(QueryResultFilePath);
}

public class Browse
{

    public void selectFile(string propertyName)
    {
        ...
        propertyName = browserWindow.FileName;  
    }
}

ここで、2番目のメソッドを変更して文字列を返し、最初の例のプロパティに手動で割り当てる必要があることに気付きました。

メソッドの実際のパラメーターとしてrefタイプを割り当てたときに、スタック上の値のコピー(つまり、ヒープ内のメモリアドレス)がスタック上の新しい場所にコピーされたと思ったのは不確かです。メソッドは仮パラメータであるため、両方ともヒープ上の同じメモリアドレスを指しています。したがって、仮パラメータの値を変更すると、ヒープに格納されている値が実際に変更され、実際のパラメータ値が変更されます。

文字列を返して手動でプロパティに割り当てる必要があるため、明らかに何かが欠落しています。誰かが私が誤解しているidを指摘することができればそれを感謝します。

ありがとう。

4

3 に答える 3

3

ここで欠けている部分は次のとおりです。文字列は不変です。

参照によって渡しますが、文字列を変更しようとするとすぐに、古い文字列をそのままにして新しい文字列が作成されます。

不変性を強制した唯一の参照型だと思います。

MSDNから:

文字列は不変です。文字列オブジェクトの内容は、オブジェクトの作成後に変更することはできませんが、構文上は変更できるように見えます。たとえば、このコードを作成すると、コンパイラは実際に新しい文字列オブジェクトを作成して新しい文字シーケンスを保持し、その新しいオブジェクトがbに割り当てられます。文字列「h」は、ガベージコレクションの対象になります。

参考文献:

http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/e755cbcd-4b09-4a61-b31f-e46e48d1b2eb

メソッドで呼び出し元の文字列を「変更」する場合は、次のキーワードを使用してこれをシミュレートできます。ref

public void SelectFile(ref string propertyName)
{
    propertyName = browserWindow.FileName;  
}

この例では、パラメーターpropertyNameがメソッドで割り当てられますref。これは、使用されているため、呼び出し元が指している文字列も変更します。ここで、不変性は引き続き適用されることに注意してください。propertyName以前は文字列Aを指していましたが、割り当て後は文字列Bを指します-古い文字列Aは参照されなくなり、ガベージコレクションされます(ただし、重要なことに、まだ存在し、変更されていません-不変です)。キーワードが使用されなかった場合refでも、呼び出し元はAを指し、メソッドはBを指します。ただし、refキーワードが使用されたため、呼び出し元の変数は文字列Bを指すようになりました。

これは、次の例と同じ効果です。

static void Main(string[] args)
{
    MyClass classRef = new MyClass("A");
    PointToANewClass(ref classRef);
    // classRef now points to a brand new instance containing "B".
}

public static void PointToANewClass(ref MyClass classRef)
{
    classRef = new MyClass("B");
}

キーワードなしで上記を試してみると、クラスが参照によって渡されたとしても、「A」を含むオブジェクトを指します。refclassRef

文字列のセマンティクスとrefセマンティクスを混同しないでください。また、参照によって何かを渡すことと割り当ての間で混乱しないでください。技術的には、ものが参照によって渡されることはありません。ヒープ上のオブジェクトへのポインタは値によって渡されます。したがってref、参照型では、上記で指定された動作をします。また、使用しrefないと、呼び出し元とメソッドの間で新しい割り当てを「共有」できなくなります。メソッドは、ヒープ上のオブジェクトへのポインターの独自のコピーを受け取り、ポインターの逆参照は通常の効果をもたらします(同じ基になるものを見る)オブジェクト)ですが、ポインタに割り当てることは、ポインタの呼び出し元のコピーには影響しません。

于 2012-05-22T09:18:20.923 に答える
2

.NET Frameworkが参照パラメーターを使用する方法と、文字列で何が起こるかをようやく理解したので、AdamHouldsworthに本当に感謝しています。

.NETには、次の2種類のデータ型があります。

  • 値型:int、float、boolなどのプリミティブ型
  • 参照型:文字列を含む他のすべてのオブジェクト

参照型の場合、オブジェクトはヒープに格納され、変数はこのオブジェクトを指す参照のみを保持します。参照を介してオブジェクトのプロパティにアクセスし、それらを変更できます。この変数の1つをパラメーターとして渡すと、同じオブジェクトを指す参照のコピーがメソッド本体に渡されます。したがって、プロパティにアクセスして変更すると、ヒープに格納されているのと同じオブジェクトが変更されます。つまり、このクラスは参照オブジェクトです。

    public class ClassOne
    {
        public string Desc { get; set; }
    }

あなたがこれをするとき

    ClassOne one = new { Desc = "I'm a class one!" };

参照によって示されるヒープ上にオブジェクトがありますone。これを行う場合:

    one.Desc = "Changed value!";

ヒープ上のオブジェクトが変更されました。この参照をパラメーターとして渡す場合:

    public void ChangeOne(ClassOne one)
    {
        one.Desc = "Changed value!"
    }

oneヒープ上の同じオブジェクトを指す元の参照のコピーを保持しているため、ヒープ上の元のオブジェクトも変更されます。

しかし、これを行う場合:

    public void ChangeOne(ClassOne one)
    {
        one = new ClassOne { Desc ="Changed value!" };
    }

元のオブジェクトは変更されていません。これoneは、参照のコピーが別のオブジェクトを指しているためです。

参照により明示的に渡す場合:

    public void ChangeOne(ref ClassOne one)
    {
        one = new ClassOne { Desc ="Changed value!" };
    }

oneこのメソッドの内部には、外部参照のコピーではなく、参照自体が含まれているため、元の参照はこの新しいオブジェクトを指します。

文字列は不変です。これは、文字列を変更できないことを意味します。そうしようとすると、新しい文字列が作成されます。したがって、これを行う場合:

  string s = "HELL";
  s = s + "O";

2行目は、値が「HELLO」で「HELL」がヒープ上に破棄された(ガベージコレクションのために残された)文字列の新しいインスタンスを作成します。

したがって、次のようなパラメータとして渡すと、変更できません。

    public void AppendO(string one)
    {
        one = one + "O";
    }

    string original =  "HELL";
    AppendO(original);

original文字列はそのままです。関数内のコードは新しいオブジェクトを作成し、それを元の参照のコピーであるオブジェクトに割り当てます。しかし、オリジナルは「地獄」を指さし続けます。

値型の場合、それらがパラメーターとして関数に渡されると、値によって渡されます。つまり、関数は元の値のコピーを受け取ります。したがって、関数本体内のオブジェクトに加えられた変更は、関数外の元の値には影響しません。

問題は、文字列は参照型ですが、値型のように動作するように見えることです(これは、比較やパラメーターの受け渡しなどに適用されます)。

refただし、上で説明したように、キーワードを使用して参照することにより、コンパイラーに参照型を渡すことができます。これは文字列でも機能します。

このコードを確認すると、文字列が変更されていることがわかります(これは、、またはその他の値型にも適用されますintfloat

    public static class StringTest
    {
        public static void AppednO(ref string toModify)
        {
            toModify = toModify + "O";
        }
    }

    // test:
    string hell = "HELL";
    StringTest.AppendO(ref hell);
    if (hell == "HELLO")
    {
       // here, hell is "HELLO"
    }

エラーを回避するために、パラメーターをrefとして定義する場合は、この修飾子を使用してパラメーターを渡す必要があることに注意してください。

とにかく、この場合(および同様の場合)は、より自然な機能構文を使用することをお勧めします。

  var hell = StringTest.AppendO(hell);

(もちろん、この場合、関数にはこのシグネチャと対応する実装があります。

  public static string AppendO(string value)
  {
      return value + "O";
  }

文字列に多くの変更を加える場合は、「可変文字列」で機能するStringBuilderクラスを使用する必要があります。

文字列型のプロパティがどのように渡されるか

于 2012-05-22T10:00:01.530 に答える
1

文字列は不変であるため、文字列のコピーをメソッドに渡します。これは、コピーは変更されますが、元のパラメーターは同じままであることを意味します。

于 2012-05-22T09:18:24.220 に答える