所谓函数或方法,只是一段代码的入口点,可以理解为主程序的一次中断调用,调用后恢复现场,也就是说,是在堆栈中分配的一块区域来处理中断事件.如果你指望去传递一个在堆内分配的一整段数据,简直是在发疯,所以传递的参数都是引用(值类型也是指针操作的,什么都有地址的)

C#中方法的参数有四种类型:

1.值参数:不含任何修饰符。方法中的形参是实参的一份拷贝(副本),形参的改变不会影响到内存中实参的的值,实参是安全的。

2.引用参数:以ref修饰符声明。传递的参数实际上是实参的指针,所以在方法中的操作都是直接对实参进行的,而不是复制一个值;可以利用这个方式在方法调用时双向传递参数;为了以ref方式使用参数,必须在方法声明和方法调用中都明确地指定ref关键字,并且实参变量在传递给方法前必须进行初始化。

3.输出参数:以out修饰符声明。和ref类似,它也是直接对实参进行操作。在方法声明和方法调用时都必须明确地指定out关键字。out参数声明方式不要求变量传递给方法前进行初始化,因为它的含义只是用作输出目的。但是,在方法返回前,必须对out参数进行赋值。

4.数组型参数:以params修饰符声明。params关键字用来声明可变长度的参数列表。方法声明中只能包含一个params参数。

按引用传递值类型是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的

方法修改该引用所引用的对象,因为引用本身是按引用来传递的。

 

自己解释一下,(值类型和引用类型的地址放在堆栈中,引用的对象放在堆中)

c#中都是传的都是堆栈的内容(int型直接就在栈里面了)

1.如果是值类型的传值(默认),那么不管是值类型或者是引用类型,那么传的堆栈内容是它本生的一个副本.

2.如果是引用类型传值(ref,out),传递的参数实际上是参数的实际指针,所以在方法中的操作都是直接对他进行的

在这里为大家解一下疑惑

public class _class
{
    public string w = "A";
}

方法1

    public void ww(_class j)
    {
        _class jj = new _class();

        jj.w = jj.w + "2";
        j = jj;
    }

方法2

    public void ww(ref _class j)
    {
        _class jj = new _class();

        jj.w = jj.w + "2";
        j = jj;
    }

方法3

 

    public void ww(_class j)
    {

        j.w = j.w + "2";
    }

1.调用方法1时发现参数j执行完方法没有变化,说明没有影响参数的值

2.调用方法2时发现参数j执行完方法变为了jj,说明变化可以更改

3.实际这个最有意思,你会发现这时候参数j发生了变化,改这个对象的属性竟然可以改变值,比较方法1和3会得出结论

虽然值传递引用类型时是传递一个副本,但是这时候在方法内部调用这个引用中的对象时,竟然是真实地址的传递,可以修改,所以,值传递应该只保护传递类型的本身,却没有为类型内部的类型创建副本,所以可以直接修改

所以在网上看到有人说数组值传递时也可以在方法内部修改,那是因为直接修改数组内部的值了,如果你新建一个数组,再直接赋值给这个参数数组,修改肯定是无效的

 

本人还是建议尽量不用ref还有尽量用返回值处理方法,代码可读性和可控性都比ref强