简体   繁体   中英

'out' modifier in C#

Possible Duplicate:
C# - Reference type still needs pass by ref?

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;
    }

I am new to C# and learning out modifier. I came across this snippet on MSDN .

I understand out is useful here for int primitive variable, but for string variables, references will be passed to the called method even without the out modifier, right?

references will be passed to the called method even without the out modifier, right?

Yes, but without out they will not be passed back:

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 is designed as immutable. You are probably thinking about mutable reference types:

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
}

but for string variables, references will be passed to the called method even without out modifier, right?

Yes, but you can't change the reference itself. When you set s1 = "I've been returned"; inside of the method, you're assigning a new string instance to the s1 variable. The variable itself is passed by value, so the calling function doesn't see this assignment.

This is more clear if you have a class:

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

If you pass this into a method without ref or out, you can still see changes inside of the instance, as it's passing the reference:

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

With this, you can call:

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

However, if you set the value to a different instance:

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

This won't show up:

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

By passing by ref or out, you allow the variable itself to be reassigned:

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

Here is the difference: If it is not out then the value in the caller is not updated.

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!";
}

Note that null for str2 in your sample is actually coming from Method. You just can't see the difference as it is null before and after the call.

You are required to set out parameters before returning from a method. So it doesn't matter what is passed in, as it is guaranteed to be overwritten.

Although variables passed as out arguments do not have to be initialized before being passed, the called method is required to assign a value before the method returns.

It is a little off-topic for your main question, but I thought this might help you better understand the purpose of the out modifier.

The other useful pattern for out parameters is seen in methods like Int32.TryParse(String value, out int i) which allow you to write code that doesn't have to manually handle common exceptions, for example,

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

That's a trivial example, but it's a fairly common and useful pattern to try and do some operation and return both whether it succeeded and a resulting value.

Another more widely used example of this in .NET is the TryGetValue() method on a dictionary - see Dictionary.TryGetValue Method (TKey, TValue) (MSDN).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM