博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

数组作为参数传递时的注意事项

Posted on 2010-12-16 20:13  风-  阅读(1694)  评论(0)    收藏  举报

在C#中的参数传递中,数组默认是按引用传递的,这意味着我们把一个数组传递到方法后,方法便可以更改这个数组内的任意元素,这在某些时候是非常有用的;

  但我们应该考虑别外一种情况:我们传递给方法的是一个临时数组,将会发生什么事情?在方法中这个数组可能被定义为某个很重要的信息,也一个结构或者是一个可序列化的类的属性,这时如果我们不加考虑地把这个临时数组传递到方法内,后果可想而知。

  这个,我们应该避免按引用的方式传递数组,但.NET好像并没有设计按值传递的方法传递数组(如果我说错了,请原谅我的无知),一种折衷的方案是使用Array类的Copy方法将数组内的元素拷贝到目标数组。来看一段测试代码:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestArrayReference
{
    class Program
    {
        static int[] A;
        static int[] B;

        static void Main(string[] args)
        {
            /*  注意请不要拿string数组做测试,
                因为string类型本身是不支持内容变动的,
                所有对string类型变量(对象)进行的更改都将产生一个新的string类型的临时变量*/
            A = new int[] { 1, 2, 3 };
            B = new int[] { 0, 0, 0 };
            //打印数组
            Console.Write("数组A:");
            PrintArray(A);
            Console.Write("数组B:");
            PrintArray(B);

        startTest:
            Console.Write("测试传址还是传值?(a/b)");
            //根据输入,判断将要执行哪个测试
            ConsoleKeyInfo cki = Console.ReadKey();
            Console.WriteLine();
            Console.WriteLine();
            switch (cki.Key)
            {
                case ConsoleKey.A:
                    Console.WriteLine("开始传址测试");
                    TestByRef(A);
                    break;
                case ConsoleKey.B:
                    Console.WriteLine("开始传值测试");
                    TestByVal(A);
                    break;
                default:
                    goto startTest;
            }

            ////更新数组A
            Console.WriteLine();
            Console.Write("更新数组A为:");
            for (int i = 0; i < A.Length; i++)
            {
                A[i] = A[i] + 1;
                Console.Write(A[i]);
            }
            Console.WriteLine();

            ////打印数组A
            Console.WriteLine();
            Console.WriteLine("现在两个数组的内容是:");
            Console.Write("数组A:");
            PrintArray(A);
            Console.Write("数组B:");
            PrintArray(B);
            ////程序结束
            Console.ReadKey();

        }
        static void PrintArray(int[] array)
        {
            foreach (int i in array)
            { Console.Write(" " + i.ToString()); }
            Console.WriteLine();

        }
        static void TestByVal(int[] array)
        {
            Console.WriteLine("以传值方式,将数组A赋给数组B");
            Array.Copy(array, B, array.Length);           
        }
        static void TestByRef(int[] array)
        {
            Console.WriteLine("以传址方式,将数组A赋给数组B");
            B = array;           
        }

    }
}

在这段代码里,执行TestByRef 方法时,将数组B设置成了对数组A的引用,那么在数组A变动后,数组B中的元素自然也会跟着变动,因为它已经是对数组A的引用,说白了它们两个是内存中的同一块区域。

 



而在执行TestByVal()方法时,只是将数组A的值拷贝到了数组B,数组A与数组B仍保持对原有内存地址的引用,彼此自身的改变也就不会影响到对方。