在编程中,我们常常需要处理引用类型对象,而将引用类型对象作为参数传递给方法时,有值参数和引用参数这两种方式,它们在方法内部操作时会产生不同的结果。下面就来详细分析这两种情况。
引用类型对象作为值参数传递
当我们把引用类型对象作为值参数传递给方法时,如果在方法内部创建一个新对象并赋值给形参,会切断形参与实参之间的关联,并且在方法调用结束后,新对象也将不复存在。
下面是一段示例代码:
class MyClass
{
public int Val = 20;
}
class Program
{
static void RefAsParameter(MyClass f1)
{
f1.Val = 50;
Console.WriteLine($"After member assignment:{f1.Val}");
f1 = new MyClass();
Console.WriteLine($"After new object creation:{f1.Val}");
}
static void Main()
{
MyClass a1 = new MyClass();
Console.WriteLine($"Before method call: {a1.Val}");
RefAsParameter(a1);
Console.WriteLine($"After method call:{a1.Val}");
}
}
从代码执行过程来看:
- 方法开始时:实参和形参指向堆中相同的对象。
- 为对象成员赋值后:它们仍指向堆中相同的对象。
- 方法分配新对象并赋值给形参时:(方法外部的)实参仍指向原始对象,而形参指向的是新对象。
- 方法调用之后:实参指向原始对象,形参和新对象都会消失。
引用类型对象作为引用参数传递
若将引用类型对象作为引用参数传递,除了在方法声明和方法调用时要使用 ref 关键字外,代码结构与值参数传递时类似。但在方法内部操作的结果却大不相同。如果在方法内创建一个新对象并赋值给形参,在方法结束后该对象依然存在,并且是实参所引用的值。
示例代码如下:
class MyClass
{
public int Val = 20;
}
class Program
{
static void RefAsParameter(ref MyClass f1)
{
//设置对象成员
f1.Val = 50;
Console.WriteLine($"After member assignment:{f1.Val}");
//创建新对象并赋值给形参
f1 = new MyClass();
Console.WriteLine($"After new object creation:{f1.Val}");
}
static void Main(string[] args)
{
MyClass a1 = new MyClass();
Console.WriteLine($"Before method call:{a1.Val}");
RefAsParameter(ref a1);
Console.WriteLine($"After method call:{a1.Val}");
}
}
这里代码的执行过程如下:
- 方法调用时:形参和实参指向堆中相同的对象。
- 对成员值修改时:会同时影响到形参和实参。
- 方法创建新对象并赋值给形参时:形参和实参的引用都指向该新对象。
- 方法结束后:实参指向在方法内创建的新对象。
综上所述,在使用引用类型对象作为参数传递时,我们需要根据具体的需求来选择使用值参数还是引用参数,避免出现意外的结果。掌握这两种参数传递方式的区别,有助于我们编写出更加健壮和高效的代码。