4

重複の可能性:
C# - 参照型は参照渡しが必要ですか?

class OutReturnExample
{
    static void Method(out int i, out string s1, out string s2)
    {
        i = 44;
        s1 = "I've been returned";
        s2 = null;
    }
    static void Main()
    {
        int value;
        string str1, str2;
        Method(out value, out str1, out str2);
        // value is now 44
        // str1 is now "I've been returned"
        // str2 is (still) null;
    }

私はC#が初めてで、修飾子を学習しています。MSDN でこのスニペットに出会いました。

outここで int プリミティブ変数の場合に役立つことは理解していますが、文字列変数の場合、参照はout修飾子がなくても呼び出されたメソッドに渡されますよね?

4

5 に答える 5

10

out参照は、修飾子がなくても呼び出されたメソッドに渡されますよね?

はい。ただし、outそれらがないと返されません:

void M(string s1, out string s2)
{
    s1 = "one";
    s2 = "two";
}

void Main()
{
    string s = "hello", t = "world";
    // s = "hello"
    // t = "world"
    M(s, out t);
    // s = "hello"
    // t = "two"
}

string不変として設計されています。おそらく、可変参照型について考えているでしょう。

class Person { public string Name { get; set; } }

void Main()
{
    var p = new Person { Name = "Homer" };
    // p != null
    // p.Name = "Homer"
    M2(p);
    // p != null
    // p.Name = "Bart"
}

void M2(Person q)
{
    q.Name = "Bart";   // q references same object as p
    q = null;          // no effect, q is a copy of p
}
于 2012-08-31T19:56:23.280 に答える
3

しかし、文字列変数の場合、out修飾子がなくても、参照は呼び出されたメソッドに渡されますよね?

はい。ただし、参照自体を変更することはできません。メソッド内で設定するとs1 = "I've been returned";、新しい文字列インスタンスがs1変数に割り当てられます。変数自体は値によって渡されるため、呼び出し元の関数はこの割り当てを認識しません。

クラスがある場合、これはより明確になります。

class Foo
{
     public string Value { get; set; }
}

これをrefまたはoutなしでメソッドに渡すと、参照を渡すため、インスタンス内の変更を確認できます。

static void Method(Foo foo)
{
    foo.Value = "Bar";
}

これで、あなたは呼び出すことができます:

Foo foo = new Foo { Value = "Foo" };
Method(foo);
Console.WriteLine(foo.Value); // Prints Bar

ただし、値を別のインスタンスに設定した場合:

static void Method2(Foo foo)
{
    foo = new Foo {Value = "Bar" };
}

これは表示されません:

Foo foo = new Foo { Value = "Foo" };
Method2(foo);
Console.WriteLine(foo.Value); // Prints Foo, not Bar!

refまたはoutを渡すことにより、変数自体を再割り当てできます。

static void Method3(ref Foo foo)
{
    foo = new Foo {Value = "Bar" };
}


Foo foo = new Foo { Value = "Foo" };
Method3(ref foo); // This will change what foo references now
Console.WriteLine(foo.Value); // Prints Bar again
于 2012-08-31T19:57:41.140 に答える
3

違いは次のとおりです。そうでない場合out、呼び出し元の値は更新されません。

static void Method(string s1, out string s2)
{
    s1 = "I've been returned";
    s2 = "changed!!!";
}

static void Main()
{
    string str1 = "one";
    string str2 "two";
    Method(str1, out str2);
    // str1 is still "one"
    // str2 is "changed!";
}

nullサンプルのforstr2は、実際にはメソッドからのものであることに注意してください。呼び出しの前後はnullであるため、違いを確認することはできません。

于 2012-08-31T19:58:47.063 に答える
0

outこれはあなたの主な質問には少し外れたトピックですが、これは修飾子の目的をよりよく理解するのに役立つかもしれないと思いました。

パラメータの他の便利なパターンは、一般的な例外を手動で処理する必要のないコードを記述できるoutようなメソッドに見られます。たとえば、Int32.TryParse(String value, out int i)

int i;
if (Int32.TryParse("blah", out i))
{
  Console.WriteLine("Valid Integer");
}
else
{
  Console.WriteLine("Invalid input");
}

これは簡単な例ですが、何らかの操作を試みて、成功したかどうかと結果の値の両方を返すことは、かなり一般的で便利なパターンです。

.NETで広く使用されているもう1つの例は、ディクショナリのメソッドです。Dictionary.TryGetValueメソッド(TKey、TValue)(MSDN)TryGetValue()を参照してください。

于 2012-08-31T20:01:27.937 に答える
0

メソッドから戻る前にパラメータを設定する必要があります。上書きされることが保証されているため、何が渡されても問題ありません。out

out 引数として渡される変数は、渡す前に初期化する必要はありませんが、呼び出されたメソッドは、メソッドが戻る前に値を割り当てる必要があります。

于 2012-08-31T19:57:39.373 に答える