C#类和对象(五)——按值和按引用传递参数

假设有一个类型A,它有一个int类型的属性X。ChangeA方法接收类型A的参数,把X的值改为2。

public static void ChangeA( A a)

{

a.X = 2;

}

Main()方法创建类型A的实例,把X初始化为1,调用ChangeA方法:

static void Main()

{

A a1 = new A { X = 1};

ChangeA( a1);

WriteLine($"a1.X: {a1. X}");

}

输出是什么?1还是2?答案视情况而定。需要知道A是一个类还是结构。下面先假定A是结构:

public struct A

{

public int X { get; set; }

}

结构按值传递,通过按值传递,ChangeA方法中的变量a得到堆栈中变量a1的一个副本。在方法ChangeA的最后修改、销毁副本。a1的内容从不改变,一直是1。

A作为一个类时,是完全不同的:

public class A

{

public int X { get; set; }

}

类按引用传递。这样,a变量把堆上的同一个对象引用为变量a1。当ChangeA修改a的X属性值时,把它改为a1.X,因为它是同一个对象。这里,结果是2。

1、ref 参数

也可以通过引用传递结构。如果A是结构类型,就添加ref修饰符,修改ChangeA方法的声明,通过引用传递变量:

public static void ChangeA( ref A a)

{

a.X = 2;

}

从调用端也可以看出这一点,所以给方法参数应用了ref修饰符后,在调用方法时需要添加它:

static void Main()

{

A a1 = new A { X = 1 };

ChangeA(ref a1);

WriteLine($" a1. X: {a1. X}");

}

现在,与类类型一样,结构也按引用传递,所以结果是2。类类型如何使用ref修饰符?下面修改ChangeA方法的实现:

public static void ChangeA( A a)

{

a.X = 2;

a = new A { X = 3 };

}

使用A类型的类,可以预期什么结果?当然,Main()方法的结果不是1,因为按引用传递是通过类类型实现的。a.X设置为2,就改变了原始对象a1。然而,下一行a=newA{X=3}现在在堆上创建一个新对象,和一个对新对象的引用。Main()方法中使用的变量a1仍然引用值为2的旧对象。ChangeA方法结束后,没有引用堆上的新对象,可以回收它。所以这里的结果是2。把A作为类类型,使用ref修饰符,传递对引用的引用(在C++术语中,是一个指向指针的指针),它允许分配一个新对象,Main()方法显示了结果 3:

public static void ChangeA( ref A a)

{

a.X = 2;

a = new A { X = 3 };

}

最后,一定要理解,C#对传递给方法的参数继续应用初始化要求。任何变量传递给方法之前,必须初始化,无论是按值还是按引用传递。

2、out 参数

如果方法返回一个值,该方法通常声明返回类型,并返回结果。如果方法返回多个值,可能类型还不同,该怎么办?这有不同的选项。一个选项是声明类和结构,把应该返回的所有信息都定义为该类型的成员。另一个选项是使用元组类型。第三个选项是使用out关键字。

下面的例子使用通过Int32类型定义的Parse方法。ReadLine方法获取用户输入的字符串。假设用户输入一个数字,int.Parse方法把它转换为字符串,并返回该数字:

string input1 = ReadLine();

int n = int.Parse( input1);

WriteLine($"n: {n}");

 

然而,用户并不总是输入希望他们输入的数据。如果用户没有输入数字,就会抛出一个异常。当然,可以捕获异常,并相应地处理用户,但“正常”情况不这么做。也许可以认为,“正常”情况就是用户输入了错误的数据。

要处理类型错误的数据,更好的方法是使用Int32类型的另一个方法:TryParse。TryParse声明为无论解析成功与否,都返回一个bool类型。解析的结果(如果成功)是使用out修饰符返回一个参数:

public static bool TryParse( string s, out int result);

调用这个方法,result变量需要在调用这个方法之前定义。使用out参数,变量不需要预先初始化,变量在方法中初始化。类似于ref关键字,out关键字也需要在调用方法时提供,而不仅仅在声明方法时提供:

string input2 = ReadLine();

int result;

if (int.TryParse( input2, out result))

{

WriteLine($" n: {n}");

}

else

{

WriteLine("不是一个数字!");

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

掌控自身命运

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值