C#参数的传值与输出

一、值参数、值类型参数、引用参数、引用类型参数的分类

如下图所示
值参数引用参数的划分关键是看有没有特殊修饰符修饰(ref 或out)的修饰。
值类型参数引用类型参数的划分则是根据在方法中声明与定义的参数类型而不是修饰符
在这里插入图片描述

二、参数的传值

1.值类型的传值参数

class Program
{
    static void Main(string[] args)
    {
        int y=100;
        Console.WriteLine(y);
		SomeMethod(y);
        Console.WriteLine(y);
    }

    static void SomeMethod(int y)
    {
       y++;
       Console.WriteLine(y);
    }
}

运行结果
在这里插入图片描述
如下图所示,与传统C语言中的参数传递相同,外部实参传递给形参,形参会在栈中获得与一块内存,保存与实参相同的数值,方法被调用过程中也只会对形参这一块临时内存中的数据进行加工,得到新值。这一过程中始终不会改变外部实参的值。
在这里插入图片描述

2、引用类型做值参数传递,不创建新对象

 class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student("小明") ;
            SomeMethod(stu1);
            Console.WriteLine(stu1.Name);
            Console.WriteLine(stu1.GetHashCode());
        }
         static void SomeMethod(Student stu)
        {
            stu.Name = "小李";
            Console.WriteLine(stu.Name);
            Console.WriteLine(stu.GetHashCode());
        }
    }
    class Student
    {
        public string Name { get; set; }
        public Student(string name)
        {
            this.Name=name;
            Console.WriteLine(this.Name);
            Console.WriteLine(this.GetHashCode());		//打印当前对象哈希值
        }
    }

运行结果
在这里插入图片描述
通过上面的例子,我们知道当引用类型做值参数传递时,类似C语言中的地址传递。由于引用类型参数本身保存的是一个实际存储数据的堆地址,因此将改地址传入方法并调用后,形参与实参指向的是同一个对象(同一块存储区域,同一对象的哈希值相同),方法被调用后对形参的加工也会是实参发生变化。
在这里插入图片描述

3、引用类型做值参数传递,并创建新对象

 class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student("小明") ;
            SomeMethod(stu1);
            Console.WriteLine(stu1.Name);
            Console.WriteLine(stu1.GetHashCode());
        }
         static void SomeMethod(Student stu)
        {
            stu = new Student("小李");            
        }
    }
    class Student
    {
        public string Name { get; set; }
        public Student(string name)
        {
            this.Name=name;
            Console.WriteLine(this.Name);
            Console.WriteLine(this.GetHashCode()); //打印当前对象哈希值
        }
    }

运行结果
在这里插入图片描述
引用类型做值参数传递,并在方法中创建新对象。与之前不同的是形参一开始得到了与实参相同地址的对象,但是在方法的调用过程中又实例化了一个新的对象给形参,导致方法对形参的一切加工都不会对实参对象起作用(形参实参分别指向两个不同的对象,哈希值不同)
在这里插入图片描述

4、值类型做引用参数传递

    class Program
    {
        static void Main(string[] args)
        {
            int y = 100;
            Console.WriteLine(y);
            SomeMethod(ref y);
            Console.WriteLine(y);
        }

        static void SomeMethod(ref int y)
        {
            y++;
            Console.WriteLine(y);
        }
    }

在这里插入图片描述
值类型参数做引用参数传递时,实际上就是在值参数传递的基础上加入了ref修饰。加入ref修饰后实参与形参间的传递不是简单的值传递,而是将实参的地址传递给了形参作为形参的地址。与之相匹配的在调用引用参数方法时也需要在对应的实参前加上ref
在这里插入图片描述

5、引用类型做引用参数进行值传递,不创建新对象

 class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student("小明") ;
            SomeMethod(stu1);
            Console.WriteLine(stu1.Name);
            Console.WriteLine(stu1.GetHashCode());
        }
         static void SomeMethod(Student stu)
        {
            stu.Name = "小李";
            Console.WriteLine(stu.Name);
            Console.WriteLine(stu.GetHashCode());
        }
    }
    class Student
    {
        public string Name { get; set; }
        public Student(string name)
        {
            this.Name=name;
            Console.WriteLine(this.Name);
            Console.WriteLine(this.GetHashCode());		//打印当前对象哈希值
        }
    }

在这里插入图片描述
引用类型做引用参数传递,不创建新对象。效果与引用类型做值参数传递相同,但在实现方式上略有不同。引用类型做值参数传递时,实参与形参的地址不同各自有一块内存区域,但两块区域内保存着相同的值(都是同一个对象的堆地址),而在引用类型做引用参数传递时,实参与形参地址相同,指向的都是同一块内存区域。
在这里插入图片描述

6、引用类型作为引用参数传递,并创建新的对象

class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student("小明");
            SomeMethod(ref stu1);
            Console.WriteLine(stu1.Name);
            Console.WriteLine(stu1.GetHashCode());
        }
        static void SomeMethod(ref Student stu)
        {
            stu = new Student("小李");
        }
    }
    class Student
    {
        public string Name { get; set; }
        public Student(string name)
        {
            this.Name = name;
            Console.WriteLine(this.Name);
            Console.WriteLine(this.GetHashCode()); //打印当前对象哈希值
        }
    }

在这里插入图片描述
从结果分析我们发现,与之前作为值参数创建对象不同,由于做引用参数时,实参与形参指向同一内存地址,所以操作形参与操作实参等价,形参被重新实例化一个对象后,实参指向的对象也会改变。
在这里插入图片描述

总结:

不加ref修饰的值参数在实参与形参传递过程中传递的是,实参的值形参都会开辟一块自己的栈内存用来拷贝实参的数据。
在加入ref修饰后形参直接获得实参的地址,操作形参与操作实参等价。

三、输出参数

**输出型参数的作用:**在调用方法时我们往往希望一个方法能有多个输出,而方法的返回值一般只有一个,为了能输出更多的数据,我们引入输出参数。
**输出参数与引用参数的对比:**与输出参数类似在方法调用中相应的输出参数前需要加上out关键字,实现的原理也与输出参数相同,实参与形参间传递的是地址,且形参不会额外申请内存空间。因此对形参的操作会同样影响到实参。两者的区别在于引入参数作为输入,在被方法调用前必须先被初始化赋值,而输出参数不需要。

在这里插入图片描述

四、数组参数

通常我们传递一个从参数时,采用的都是一个数组作为实参传递给形参,但有些情况下,我们需要临时传递一个数组,如果需要额外的定义和修改一个临时数组传入就会显得有点麻烦,这时我们就可以使用param关键字将方法中的传入参数声明为数组参数。

class Program
{
    static void Main(string[] args)
    {
        int result = CalculateSum(1, 2, 3);      //调用方法时可以直接输入数组的成员,而不需要再额外定义一个数组在赋值
        Console.WriteLine(result);
    }

    static int CalculateSum(params int[] intArray)   //声明该参数是一个数组参数
    {
        int sum = 0;
        foreach (var item in intArray)
        {
            sum += item;
        }

        return sum;
    }
}

值得注意的,若方法中有多个参数数组参数必须是最后一个参数。

五、具名参数

具名参数不具有特殊关键字,只是在调用某一方法时采用 形参名:实参的格式,参数的位置不在受方法参数列表约束。
采用具名参数最大的优势是可以提高代码可读性。

class Program
{
    static void Main(string[] args)
    {
        PrintInfo("Tim", 34);

        PrintInfo(age: 24, name:"Wonder");           //具名参数调用
    }

    static void PrintInfo(string name, int age)
    {
        Console.WriteLine("Helllo {0}, you are {1}.",name,age);
    }
}

六、扩展方法(this参数)

使用扩展方法可以给一个以声明的类型进行方法扩展。

class Program
{
    static void Main(string[] args)
    {
        double x = 3.14159;
        // double 类型本身没有 Round 方法,只能使用 Math.Round。
        double y = x.Round(4);         //扩展后可以直接调用扩展的方法,X的值会直接传递给this修饰的参数
        Console.WriteLine(y);
    }
}

static class DoubleExtension                      //扩展Double类的方法   类名+Extension
{
    public static double Round(this double input,int digits)        //添加Round 方法,这里this参数修饰的input输入的就是调用该方法的对象的值
    {
        return Math.Round(input, digits);
    }
}

在这里插入图片描述

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读