pro*_*eek 7 .net c# string ref
在stringC#中的类型是引用类型,并通过值拷贝传递引用类型参数的参考,这样我就不需要使用ref修改器.但是,我需要使用ref修饰符来修改输入string.为什么是这样?
using System;
class TestIt
{
static void Function(ref string input)
{
input = "modified";
}
static void Function2(int[] val) // Don't need ref for reference type
{
val[0] = 100;
}
static void Main()
{
string input = "original";
Console.WriteLine(input);
Function(ref input); // Need ref to modify the input
Console.WriteLine(input);
int[] val = new int[10];
val[0] = 1;
Function2(val);
Console.WriteLine(val[0]);
}
}
Run Code Online (Sandbox Code Playgroud)
dle*_*lev 14
您需要引用字符串参数的原因是,即使您传入对字符串对象的引用,为参数指定其他内容也只会替换当前存储在参数变量中的引用.换句话说,您已更改参数引用的内容,但原始对象未更改.
当你引用参数时,你告诉函数该参数实际上是传入变量的别名,因此赋值给它会产生预期的效果.
编辑:请注意,虽然字符串是一个不可变的引用类型,这在这里不太相关.由于您只是尝试分配一个新对象(在这种情况下是字符串对象"已修改"),因此您的方法不适用于任何引用类型.例如,考虑对您的代码稍作修改:
using System;
class TestIt
{
static void Function(ref string input)
{
input = "modified";
}
static void Function2(int[] val) // don't need ref for reference type
{
val = new int[10]; // Change: create and assign a new array to the parameter variable
val[0] = 100;
}
static void Main()
{
string input = "original";
Console.WriteLine(input);
Function(ref input); // need ref to modify the input
Console.WriteLine(input);
int[] val = new int[10];
val[0] = 1;
Function2(val);
Console.WriteLine(val[0]); // This line still prints 1, not 100!
}
}
Run Code Online (Sandbox Code Playgroud)
现在,数组测试"失败",因为您正在为非ref参数变量分配新对象.
它有助于比较string类似string但可变的类型.让我们看一个简短的例子StringBuilder:
public void Caller1()
{
var builder = new StringBuilder("input");
Console.WriteLine("Before: {0}", builder.ToString());
ChangeBuilder(builder);
Console.WriteLine("After: {0}", builder.ToString());
}
public void ChangeBuilder(StringBuilder builder)
{
builder.Clear();
builder.Append("output");
}
Run Code Online (Sandbox Code Playgroud)
这会产生:
Before: input
After: output
Run Code Online (Sandbox Code Playgroud)
所以我们看到对于一个可变类型,即一个可以修改其值的类型,可以将对该类型的引用传递给类似的方法ChangeBuilder而不是使用ref或者out在我们调用之后仍然将值更改.
请注意,我们在任何时候都没有实际设置builder为不同的值ChangeBuilder.
相比之下,如果我们用字符串做同样的事情:
public void Caller2()
{
var s = "input";
Console.WriteLine("Before: {0}", s);
TryToChangeString(s);
Console.WriteLine("After: {0}", s);
}
public void TryToChangeString(string s)
{
s = "output";
}
Run Code Online (Sandbox Code Playgroud)
这会产生:
Before: input
After: input
Run Code Online (Sandbox Code Playgroud)
为什么?因为TryToChangeString我们实际上并没有改变变量引用的字符串的内容,所以s我们将替换 s为一个全新的字符串.此外,s是一个局部变量TryToChangeString,因此替换函数s 内部的值对传递给函数调用的变量没有影响.
因为string是一成不变的,没有办法,不使用ref或out以影响呼叫者的字符串.
最后,最后一个例子做了我们想要的string:
public void Caller3()
{
var s = "input";
Console.WriteLine("Before: {0}", s);
ChangeString(ref s);
Console.WriteLine("After: {0}", s);
}
public void ChangeString(ref string s)
{
s = "output";
}
Run Code Online (Sandbox Code Playgroud)
这会产生:
Before: input
After: output
Run Code Online (Sandbox Code Playgroud)
该ref参数实际上使两个s变量彼此别名.就好像它们是同一个变量.
字符串是不可变的 - 您不是在修改字符串,而是将引用指向的对象替换为另一个.
将其与例如List相比较:要添加Items,您不需要ref.要用不同的对象替换整个列表,您需要ref(或out).