【问题标题】:Handling Reference Types处理引用类型
【发布时间】:2010-12-14 22:26:55
【问题描述】:

当引用变量可以通过引用传递时:

    class Example
    {
        public string str="Demo";

        public int[] intValues={1,3,4,5};

       public static void StrPassing(string someStr)
        {
            string otherStr="Changed!";
            someStr=otherStr;
        }

        public static void NumPassing(int[] a)
        {
            a[2] = 115;
        }

    }


       static void Main(string[] args)
        {
            Example ex = new Example();
            Example.StrPassing(ex.str);
            Example.NumPassing(ex.intValues);

            foreach (int i in ex.intValues)
            {
                Console.WriteLine(i);
            }

            Console.WriteLine(ex.str);
            Console.ReadLine();
        }

intValues[2]的值在传递引用时更改为115。但是字符串“str”(demo)的值没有更改为“Changed!”。这是什么原因? .我可以把它当作数组是通过引用传递的,而其他引用类型是通过传递的 价值?

【问题讨论】:

    标签: c# reference types


    【解决方案1】:

    无论您作为参数传递给方法的任何内容都是按值传递的,对于引用类型,这意味着 引用 是按值传递的。因此,您不能将 object 更改为另一个对象,但您肯定可以更改其 contents(因为这不会更改实际引用,只会更改其他地方的一些内存)。

    正如您使用数组的示例所演示的,您获取数组引用(但不要更改它)并更改数组中的值 in。这就像获取一些对象并更改属性值一样。你也可以在方法中做到这一点。

    如果你想改变一个字符串,它是.NET中的一个不可变对象,那么你需要使用ref参数:

    public static void StrPassing(ref string someStr)
    {
        string otherStr="Changed!";
        someStr=otherStr;
    }
    

    然后这样称呼它:

    string foo = "foo";
    StrPassing(ref foo);
    Console.WriteLine(foo); // should print "Changed!"
    

    ref 关键字可确保您的方法获得对字​​符串的实际引用并且可以更改它,而不仅仅是引用的副本。那么您可以用一个全新的对象替换该对象。

    回到您的数组:您也很难将传递的数组更改为完全不同的数组:

    public static void NumPassing(int[] a)
    {
        a = new int[15];
    }
    

    也不行,因为那么你会尝试与将字符串更改为完全不同的字符串完全相同。

    【讨论】:

    • 我不认为“按值引用”是一个特别有用的术语 - 将传递的内容(引用)与传递的方式(按值)分开。领先的“by”只会增加 IMO 的混乱。
    • 你是对的。我把它改成了更容易理解的东西(我希望)。现在更像你的话。 Aaaand 这是我接受的答案。德拉特。
    【解决方案2】:

    您需要区分更改变量引用哪个对象和更改*对象的内容”。

    在这段代码中:

    public static void StrPassing(string someStr)
    {
        string otherStr="Changed!";
        someStr=otherStr;
    }
    

    ...您正在更改someStr 的值。您没有对 someStr 最初引用的字符串进行任何更改。事实上,你不能因为字符串是不可变的。 (如果是StringBuilder,您可以将长度设置为 0,然后附加“已更改!”)

    更改 someStr 的值无效,因为参数 (ex.str) 是按值传递的。 (有问题的值一个引用,但这并不意味着它是通过引用传递的。)

    现在将其与以下代码进行比较:

    public static void NumPassing(int[] a)
    {
        a[2] = 115;
    }
    

    这里你没有改变a的值 - 你改变了a引用的数组的内容。

    简而言之,除非您使用 ref/out,否则参数将按值传递 - 但对于引用类型,该值只是一个引用。

    我有一个article on parameter passing,它更详细地介绍了所有这些。

    【讨论】:

      【解决方案3】:

      字符串在 C# 中是特殊的。它们是不可变的引用类型,这使得它们表现出与值类型相似的行为。

      Here's 很好的讨论。

      【讨论】:

      • 不可变并不会使它们特别——特别是,编译器不会改变它们的传递方式或类似的东西。
      【解决方案4】:

      您需要做的是将StrPassing 的签名更改为如下所示:

      public static void StrPassing(ref string someStr)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-31
        • 2017-12-25
        • 2012-03-09
        相关资源
        最近更新 更多