为什么在方法内部反转字符串数组不会持久化

时间:2014-06-18 13:13:46

标签: c# parameters

所以我有一个简单的字符串数组。将它传递给一个反转其输入的函数,然后显示数组的内容。我期待数组的内容反转,因为数组是通过引用传递的,但是字符串数组没有改变。

string[] words = { "Metal", "Gear", "is", "Awesome!" };

mutateArray(ref words);

foreach (string word in words)
     Console.Write(word + " "); 

这是我的mutateArray功能:

 public static void mutateArray(ref string[] arr)
 {
      arr = arr.Reverse().ToArray();          
 }

我知道,一旦我声明必须使用关键字mutateArray传递参数,数组的ref方法更改将会保留。

  1. 默认情况下,并非所有数组都通过引用传入吗?
  2. 为什么在涉及关键字ref时更改仍然存在?
  3. 通过值 vs 传递引用类型(classesinterfacesarraydelegates)之间的区别是什么(使用关键字ref)?

5 个答案:

答案 0 :(得分:2)

这并不是你所期望的原因是Reverse()实际上并没有反转数组的内容,而是创建了一个带有反向内容的 new 列表。原版的。这就是为什么一旦你通过引用传递数组它就可以工作的原因:然后,你实际上用在mutateArray中创建的新数组替换调用方法中的整个原始数组。

如果你有一个在原地进行反转的方法,你可以传入原始数组(不使用ref),在方法调用之后,数组的顺序会相反。

答案 1 :(得分:1)

  1. 您将参考类型与参考传递混淆。 ref关键字可以应用于值和引用类型。默认情况下,即使引用类型也没有通过引用传递。而是通过值将引用传递给方法。

  2. 根据MSDN的文档,他们应该这样做。这就是将ref关键字与参考类型结合使用的全部目的。

  3. 不同之处在于,当您通过引用传递引用类型时,您可以更改原始变量的引用,而不仅仅是方法中的实例。查看以前链接的文档以获取更多详细信息。

答案 2 :(得分:1)

  1. 默认情况下,所有参数都按值传递给C#。对于像array这样的引用类型,这意味着引用按值传递。

  2. ref使变量通过引用传递给函数。这实际上意味着arr中的mutateArray参数是调用方中words的别名。这就是arr的分配导致words退出后mutateArray的变化的原因。

  3. 按值将引用类型传递给函数意味着引用的副本。如果没有ref修饰符,arr中的mutateArray是一个不同的变量,其中包含对调用者中words的同一对象的引用。在这种情况下,分配给arr对调用者中的words没有影响。请注意,您可以通过共享引用变更数组,但arrwords是单独的存储位置。

答案 3 :(得分:0)

words是对数组的引用。只要考虑它包含该数组的内存地址。

当您将MutateArray作为参数(不包含ref关键字)提供给它时​​,其VALUE将被复制到arr中。所以arr是一个不同的变量作为单词,但它们包含相同的值(=内存地址)。这意味着它们引用相同的对象(字符串数组)。

你可以改变对象的内容,但是单词(和arr)仍然会引用它。

如果将arr指定给其他对象,则其值会更改,因此它将引用与单词不同的对象。

但是,如果使用ref关键字,则arr和words是SAME变量。这意味着如果您更改了arr的值(=将其指定给新对象),您也会更改单词的值,因此单词将引用相同的新对象。

也许所有这些在技术上都不是100%正确,但我想用它来思考它是如何工作的。

ref关键字是以下Swap方法在C#中工作的原因;没有它,它只会改变Swap方法的内部变量(并且根本没有做任何事情)

public void Swap<T>(ref T a, ref T b) {
    T temp = a;
    a = b;
    b = temp;
}

答案 4 :(得分:0)

你的问题完全可以理解,有一会儿我也很困惑 所以这是解释。

简短说明

  • 当您将引用类型传递给方法并对其属性进行更改时,方法外部的对象可以查看属性更改,因为对象本身保持不变。
  • 当您将引用类型传递给方法并对实例本身进行更改时,方法外部的对象无法查看更改,因为在方法内部您基本上开始指向另一个对象。因此,对象在方法内部发生了变化,并作为一个陌生人留在那里。

长解释

  • 假设您有一个引用类型实例,您可以从中获取数据库中的值。

        using (var context = new MyAdventureWorksEntities2())
        {
            Product p = context.Products.Where(item => item.ProductID == 1000).First();
            Console.WriteLine(p.Name); // p.Name = "INITIAL NAME"
            UpdateName(p);
            Console.WriteLine(p.Name);
        }
    

这是您的UpdateName方法:

    public static void UpdateName(Product p)
    {
        p.Name = "UPDATED NAME";
    }

此代码会发出以下结果:
INITIAL NAME
UPDATED NAME

  • 但是,如果您将方法更改为以下内容:

    public static void UpdateName(Product p)
    {
        using (var context = new MyAdventureWorksEntities2())
        {
            p = context.Products.Where(item => item.ProductID == 1003).First();
            // p.Name = "ANOTHER PRODUCT NAME"
        }
    }
    

你的结果将是:
INITIAL NAME
INITIAL NAME

请注意,我根本没有触及ref关键字 也许在这些例子之后,简短描述将更容易理解。