C# 第八弹 —————— 参数

17 篇文章 1 订阅

   可能很多人不理解为啥子这个要单独开一章,不过我得说一下,这个真的很重要,得搞清楚了,不能混淆了。

   参数分三种:值参数,引用参数和输出参数

   在这之前先说一下形参和实参的概念。

   形参:本地变量,声明在方法的参数列表中,而不是在方法体内。很正规的说法,其实很简单,举个栗子就懂了。

               eg:

public void SetParameter(int a1,float b1)
{
    ...
}

                    其中a1,b1就是形参。

   实参:用于初始化形参的表达式或变量。也说得很规范,同样的给个例子。

               eg:

static void Main()
{
  float b1 = 0;
  SetParameter(10,b1);
}

                      其中10和b1就是实参了。

说到这里形参和实参的概念是不是就懂了,下面开始说一下值参数和引用参数吧。   

值参数:通过将实参的值复制给形参的方式把数据传递到方法中。

                   要点:1.在栈中为形参分配空间

                               2.将实参的值复制给形参

引用参数:

                   要点:1.使用引用参数时,必须在方法的声明和调用中都是用ref修饰符。

                               2.实参必须是变量,在用做实参前必须被赋值。

输出参数:用于从方法体内把数据传出到调用代码,与引用参数类似。

                   要点:1.使用输出参数时,必须在方法的声明和调用中都是用out修饰符。

                               2.实参必须是变量,在方法体内被初始化,这一点与ref是不一样的地方。

这里需要说明一下ref的作用。我的理解就是一个引用指向堆里的数据,这个引用的改变会影响数据的改变。

              eg:

static int a11 = 1;
static float b11 = 2;
static void SetParameter(int a1, ref float b1)
{
   a1 = 10;
   b1 = 20;
   Console.WriteLine("a1Copy:" + a1);
   Console.WriteLine("b1Copy:" + b1);
}

static void Main()
{
   Console.WriteLine("Before:a11:{0},b11:{1}", a11, b11);
   SetParameter(a11, ref b11);
   Console.WriteLine("Late:a11:{0},b11:{1}", a11, b11);
   Console.ReadKey();
}

输出结果就是:

   

   这里可以发现如果SetParameter函数的方法体中引用形参b1改变为20的情况下,堆里的数据也会发生改变,也就是b11变成了20。这就是ref的作用了,会对堆里的数据造成影响。

   而这里又会引申出另一个问题,就是如果引用类型作为值参数和引用参数的时候会有什么不同呢。

   1.将引用类型作为值参数传递   如果在方法内创建一个新对象并赋值给形参,将切断形参与实参之间的关联,并且在方法调用结束后,新对象将不复存在(被释放掉)。

   2.将引用类型对象作为引用参数传递   如果在方法内创建一个新对象并赋值给形参,在方法结束后该对象依然存在,并且是实参所引用的值。

   有点文绉绉的,那么我们继续使用栗子。

第一种情况是这样子的:

class MyClass
{
    public int myClassData = 10;
}
class Program
{
    static void SetParameter(MyClass mc)
    {
        mc.myClassData = 20;
        Console.WriteLine("Set Data:" + mc.myClassData);
        mc = new MyClass();
        Console.WriteLine("After new then Set Data:" + mc.myClassData);
    }

    static void Main()
    {
        MyClass mc2 = new MyClass();
        Console.WriteLine("Before:" + mc2.myClassData);
        SetParameter(mc2);
        Console.WriteLine("Late:" + mc2.myClassData);
        Console.ReadKey();
    }
}

大家猜一下结果如何呢?

enmmmm,直接上结果了。

有没有意外?为什么mc2.myClassData的值会改变呢?别忘了哦,传递的是一个引用参数哦,mc2和mc是两个不同的引用指向同一个堆里的数据,而在SetParameter函数中mc重新new了一下,是不会改变mc2的值的。这就是第一种情况。

而第二种情况是这样子的:

class MyClass
{
    public int myClassData = 10;
}
class Program
{
    static void SetParameter(ref MyClass mc)
    {
        mc.myClassData = 20;
        Console.WriteLine("Set Data:" + mc.myClassData);
        mc = new MyClass();
        Console.WriteLine("After new then Set Data:" + mc.myClassData);
    }

    static void Main()
    {
        MyClass mc2 = new MyClass();
        Console.WriteLine("Before:" + mc2.myClassData);
        SetParameter(ref mc2);
        Console.WriteLine("Late:" + mc2.myClassData);
        Console.ReadKey();
    }
}

就增加了一个ref的关键字,那么结果如何呢?直接上结果了。

Late的结果俨然不同,这其中的原因就是ref的作用了。

好了,说了那么多就讲到这里了,有不懂的下面回复吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值