zoukankan      html  css  js  c++  java
  • C#基础之参数(一) 值参数、引用参数与输出参数

      要学会各种参数,重点是理解参数参数传递的内存原理。理解了内存,各种参数使用的作用、效果等便可以自己分析出来,而不用死记硬背。  

      1.按值传递参数(值参数)

        值参数是最常见的一种参数,也很好判断。在方法声明与调用时,参数前不加ref或out关键字的参数,便是按值传递。
        值参数是将实参变量在“栈”中存储的值复制一份副本,将副本传递给方法的形参。
        按值传递参数又分为两种不同情况:传递值类型,与传递引用类型
        (注意这里的值类型、引用类型是数据类型,而值参数、引用参数是参数传递方式。二者不是同一概念,不可混淆。)

        (1)传递值类型参数

        示例:

     1     class Program
     2     {
     3         static void Main(String[] args)
     4         {
     5             int a = 4;
     6             int b = 5;
     7             Add(a, b);
     8             Console.WriteLine($"a={a},b={b}");
     9         }
    10         public static void Add(int x, int y)
    11         {
    12             x += 1;
    13             y += 1;
    14         }
    15     }

        输出为:

    a=4,b=5
    

        内存原理:在Add方法中对形参x与y的操作,并不会对实参a与b的值产生影响,因为在Add方法中操作的是a与b的副本。

        (2)传递引用类型参数 

        示例1:

     1     class Program
     2     {
     3         static void Main(String[] args)
     4         {
     5             Animal a = new Animal() { Age = 1 };
     6             Add(a);
     7             Console.WriteLine($"a.Age={a.Age}");
     8         }
     9         public static void Add(Animal animal)
    10         {
    11             animal.Age += 1;
    12         }
    13     }
    14     class Animal
    15     {
    16         public int Age { get; set; }
    17     }    

        输出为:

    a.Age=2

        内存原理:

        在Add方法中形参animal拿到了实参a在栈中的副本,副本中存储着对象的地址。所以,animal与a指向了同一个对象。
           这时操作的不是副本,而是副本所指的对象,即操作a所指对象。

        示例2:

        

     1     class Program
     2     {
     3         static void Main(String[] args)
     4         {
     5             Animal a = new Animal() { Age = 1 };
     6             Add(a);
     7             Console.WriteLine($"a.Age={a.Age}");
     8         }
     9         public static void Add(Animal animal)
    10         {
    11             animal = new Animal() { Age = 10 };
    12             animal.Age += 1;
    13         }
    14     }
    15     class Animal
    16     {
    17         public int Age { get; set; }
    18     }

        输出为:

    a.Age=1
    

        内存原理:

        与示例1不同的是,在示例2中Add方法中改变了animal所指向的对象,指向一个new的Animal对象,此时a仍指向原对象,这时再对animal进行操作,
           便不再会影响实参a所指的对象。

      2.按引用传递参数(引用参数)

         形参与实参之前,都要加ref关键字。
         需要注意的是,实参在使用之前必须赋值,否则编译器会报错。(如下图)
         此时不再复制实参在栈中的副本,而是将实参在栈中的地址传给形参,也就是实参与形参共用栈中的值。此时在方法中对形参所做的任何操作,都会影响实参。
         按引用传递也分为值类型和引用类型两种情况。

        (1)传递值类型参数

        示例:

        

     1     class Program
     2     {
     3         static void Main(String[] args)
     4         {
     5             int a = 4;
     6             int b = 5;
     7             Add(ref a, ref b);
     8             Console.WriteLine($"a={a},b={b}");
     9         }
    10         public static void Add(ref int x, ref int y)
    11         {
    12             x += 1;
    13             y += 1;
    14         }
    15     }

        输出为:

    a=5,b=6

        内存原理:

        由于a与x,b与y指向了栈中相同的地址,在Add方法中对形参x与y的操作,会影响实参a与b的值。

        (2)传递引用类型参数

        示例1:

     1     class Program
     2     {
     3         static void Main(String[] args)
     4         {
     5             Animal a = new Animal() { Age = 1 };
     6             Add(ref a);
     7             Console.WriteLine($"a.Age={a.Age}");
     8         }
     9         public static void Add(ref Animal animal)
    10         {
    11             animal.Age += 1;
    12         }
    13     }
    14     class Animal
    15     {
    16         public int Age { get; set; }
    17     }

        输出为:

    a.Age=2
    

        内存原理:

        这时得到的效果,与按值传递参数是一样的,但内存原理却不相同。

        这时Add方法中形参animal指向的不再是实参a在栈中的副本的地址,而是与a指向了栈中相同的位置。

        示例2:

     1     class Program
     2     {
     3         static void Main(String[] args)
     4         {
     5             Animal a = new Animal() { Age = 1 };
     6             Add(ref a);
     7             Console.WriteLine($"a.Age={a.Age}");
     8         }
     9         public static void Add(ref Animal animal)
    10         {
    11             animal = new Animal() { Age = 10 };
    12             animal.Age += 1;
    13         }
    14     }
    15     class Animal
    16     {
    17         public int Age { get; set; }
    18     }

        输出为:

    a.Age=11
    

        内存原理:

         这个示例便可以看出与按值传递时示例2的不同。

         Add方法中改变了animal所指向的对象,指向一个new的Animal对象,此时a所指向的对象也随之改变。这是由于形参animal
         与实参a指向的是栈中相同的地址(这个地址中存储的是对象在堆中的地址)。当栈中存储的堆地址改变时,animal与a会同时指向新的对象。

      3.输出参数

        用法:
         (1)形参与实参之前,都要加out关键字。
         (2)输出参数主要是用于函数需要有多个返回值时,作为返回值使用。
        与引用变量相同的是:
         (1)输出参数也不复制实参在栈中的副本,而是将实参在栈中的地址传给形参。在这点上,输出参数与引用参数相同。
         (2)实参必须是可以赋值的变量,而不能是常亮。
        与引用参数不同的是:
         (1)实参在使用之前不必赋值。
         (2)事实上,在使用之前对实参的赋值没有任何意义,因为在调用方法的最开始,便会将其值抹去,使其成为未赋值的变量。
         (3)在方法返回之前,必须对out参数进行赋值。
        由以上特点所决定的是,输出参数无法向方法中传递信息,其唯一作用便是,当一个参数需要返回多个值时,作为返回值返回。

        示例1:

     1     class Program
     2     {
     3         static void Main(String[] args)
     4         {
     5             int a;
     6             Add(1, 2, out a);
     7             Console.WriteLine(a);
     8         }
     9         public static bool Add(int x, int y, out int result)
    10         {
    11             result = x + y;
    12             return true;
    13         }
    14     }

        输出为:

    3
    

        引用类型的输出参数同理,请自行编写示例代码。

     请继续阅读参数学习的下篇:C#基础之参数(二) 数组参数、可选参数与命名参数

        

  • 相关阅读:
    jquery获取元素各种宽高及页面宽高
    Mysql 多表联合查询效率分析及优化
    mysql连表操作是先连表还是先查询条件
    CSS实现垂直居中
    laravel中orderBy使用
    Spring官网改版后下载
    java.lang.NoClassDefFoundError: org/jaxen/JaxenException
    flex 简单跑马灯效果(竖着显示)
    Flex “跑马灯”效果(自定义“跑马灯”控件)
    当LinkButton无效时,光标不显示为手型
  • 原文地址:https://www.cnblogs.com/vsSure/p/7847204.html
Copyright © 2011-2022 走看看