2012-08-31 66 views
3

可能重复:
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; 
    } 

我是新来的C#和学习了修改。我碰到this snippet on MSDN

我知道out在这里对于int原始变量很有用,但对于字符串变量,即使没有out修饰符,引用也会传递给被调用的方法,对吧?

+1

不,不对。如果字符串参数未标记为out,则s1和s2将被视为局部变量。不要在参考文献本身,而是参考参考文献时考虑ref和out。 –

+1

对于引用类型(例如字符串),引用将按值传递。这意味着您可以更改实例的内容,但不能更改引用本身。在字符串的情况下,你甚至不能更改内容,因为它们是不可变的。 – CodesInChaos

回答

9

即使没有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 
} 
+1

+1。我soooo slooooowwwww拿出完全相同的答案:) –

0

您是需要从方法返回之前设置out parameters。所以传入的内容并不重要,因为它可以被覆盖。

虽然作为out参数传递的变量在传递之前不必被初始化,但被调用的方法需要在方法返回之前分配一个值。

3

但是对于字符串变量,即使没有修饰符,引用也会传递给被调用的方法,对吗?

是的,但你不能改变参考本身。当您在方法内设置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" }; 
} 

这将不会显示:

​​

通过用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 
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为您的样品中str2实际上是从法的到来。你只是看不到差异,因为在呼叫之后之前为空。

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另一个更广泛的应用的例子是在一个字典中的TryGetValue()方法 - 见Dictionary.TryGetValue Method (TKey, TValue)(MSDN)。