在C#函数中键入'string'作为参数

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参数变量分配新对象.


Ric*_*key 6

它有助于比较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一成不变的,没有办法,不使用refout影响呼叫者的字符串.

最后,最后一个例子做了我们想要的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变量彼此别名.就好像它们是同一个变量.


Mic*_*tum 5

字符串是不可变的 - 您不是在修改字符串,而是将引用指向的对象替换为另一个.

将其与例如List相比较:要添加Items,您不需要ref.要用不同的对象替换整个列表,您需要ref(或out).