【问题标题】:How can a method without the out or ref change a variable outside itself? C# [duplicate]没有 out 或 ref 的方法如何更改自身外部的变量? C# [重复]
【发布时间】:2014-04-04 12:11:59
【问题描述】:

如何从SumElemtnts 方法内部更改数组a 的值?是因为它是静态方法吗?因为该方法只返回变量sum,没有ref或者out。

class Program
{
    public static int SumElements(int[] a)
    {
        int[] a2 = a;
        int sum = 0;
        for (int i = 0; i < a2.Length; i++)
        {
            int temp = a2[i] * 10;
            a2[i] = temp;
            sum += temp;
        }
        a[a2.Length - 2] = sum;
        return sum;
    }

    public static void Main(string[] args)
    {
        int[] a = { 1, 2, 3 };
        int sum = SumElements(a);

        Console.Write("Sum = " + sum + ", ");
        for (int i = 0; i < a.Length; i++)
        {
            Console.Write(a[i] + " ");
        }
    }
}

结果是:

总和 = 60, 10 60 30

【问题讨论】:

    标签: c# pass-by-reference pass-by-value


    【解决方案1】:

    您没有更改 SumElements 中的变量值 - 它仍然引用与之前相同的数组。注意SumElements 方法中没有分配给a

    相反,您正在更改数组的内容。该更改在 Main 中可见,因为它仍然具有对数组的引用。

    把变量想象成一张纸。在Main 中,您有一个名为a 的变量,其中包含一个引用——一种获取数组的方式。这就像一张写有街道地址的纸。这是房子的街道地址 - 类似于数组对象。

    您正在复制该值(街道地址)并将其用作SumElementsa 的值。这两张纸是分开的——您可以在SumElements 中的一张纸上乱涂乱画,这不会改变Main 中的那张纸——但它们从相同的街道地址开始。然后SumElements 将前往该街道地址,并绘制其中一扇窗户。当Main 然后去同一个街道地址时,它也看到了画过的窗户......因为只有 一个 房子(数组对象),即使有两张相同的纸街道地址写在上面。

    有关详细信息,请参阅我在 parameter passingreference types and value types 上的文章。

    【讨论】:

    • 在这里我想在我的回答中引用你的文章:)
    • @tastro:哦,天哪 - 这些纸片的想法是让它更容易。现实世界的类比往往会帮助人们——如果这次失败了,对不起:(
    【解决方案2】:

    数组是一种引用类型。

    您不是在传递数组的副本,而是在传递对它的引用。

    这是一个较小的LINQPad 程序,演示:

    void Main()
    {
        var a = new[] { 1, 2, 3 };
        Test(a);
        a.Dump();
    }
    
    public static void Test(int[] arr)
    {
        arr[1] = 15;
    }
    

    输出:

    1
    15
    3
    

    详细说明:当您在 C# 中将值传递给方法时,默认情况下是“按值传递”,这意味着您传递的是值的副本,而不是实际的变量自己。

    在这种情况下,您传递的是 引用的副本,但引用正在引用一个数组。

    因此,该方法对数组有自己的引用,但它仍然使用与“外部”代码相同的数组。

    【讨论】:

    • 感谢您提醒我,数组和类一样是引用类型,但我不知何故忘记了这一点(我在学校就知道了)。 :) 这个声明An array is a reference type. 是你的答案是我接受的答案的原因。 stackoverflow 可以添加类似这样的内容......用户可以写下他们选择答案作为他们接受的答案的原因。
    【解决方案3】:

    你的int[] a 是一个数组(一个引用类型) 它的地址作为值传递给你的方法SumElements,现在你方法中的参数a 指向同一个对象记忆。因此,一旦您更改了特定索引的值,您就会看到调用者的变化。

    你应该看到:Parameter passing in C# by Jon Skeet

    【讨论】:

      【解决方案4】:

      原因很简单,array is reference type 所以你正在改变数组的内容

      From MSDN:

      以下示例演示了将引用类型参数 arr 按值传递给方法 Change。因为参数是对 arr 的引用,所以可以更改数组元素的值。但是,将参数重新分配到不同内存位置的尝试仅在方法内部起作用,并且不会影响原始变量 arr。 C#

      class PassingRefByVal 
      {
          static void Change(int[] pArray)
          {
              pArray[0] = 888;  // This change affects the original element.
              pArray = new int[5] {-3, -1, -2, -3, -4};   // This change is local.
              System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
          }
      
          static void Main() 
          {
              int[] arr = {1, 4, 5};
              System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]);
      
              Change(arr);
              System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
          }
      }
      
      /* Output:
          Inside Main, before calling the method, the first element is: 1
          Inside the method, the first element is: -3
          Inside Main, after calling the method, the first element is: 888
      */
      

      尝试阅读Passing Reference-Type Parameters (C# Programming Guide)这是了解更多发生的事情的最佳方式

      【讨论】:

        【解决方案5】:

        通过对数据所在地址的引用访问每个引用类型(即使未标记为引用参数)。请参阅下面哪些数据类型是引用类型以及哪些是值类型的列表。非常好的示例和技术细节可以在这里找到http://www.albahari.com/valuevsreftypes.aspx

        值类型 值类型包括:

        All numeric data types
        Boolean, Char, and Date
        All structures, even if their members are reference types
        Enumerations
        

        引用类型 引用类型包括以下:

        String
        All arrays, even if their elements are value types
        Class types, such as Form
        Delegates
        

        【讨论】:

          猜你喜欢
          • 2015-05-11
          • 2021-10-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-29
          • 2018-12-24
          • 1970-01-01
          相关资源
          最近更新 更多