引用类型参数使用ref与不使用ref的区别
2011-01-13 16:27
399 查看
我们都知道:
ref关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。(摘自msdn)。
同时我们也可以在msdn上找到这样一段话:
按引用传递值类型(如本主题前面所示)是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。下面的示例显示出当引用类型作为 ref 参数传递时,可以更改对象本身。
理解:不使用ref关键字引用类型的参数传递的是该对象(记为对象A)的引用,即对象A位于托管堆中的地址。而使用ref关键字的引用类型的参数传递的是该对象(记为对象B)引用的引用,即保存对象B位于托管堆中地址的变量(该变量位于堆栈中)的引用。即ref传递的是堆栈地址,而引用(引用类型的引用)传递的是托管堆的地址。当将ref使用在引用类型上,传递的是保存引用类型对象堆地址的栈地址,而不是堆地址。
下面用一个例子来对比使用ref和不适用ref的区别
源代码:
class Program
{
static void Main(string[] args)
{
A a1 = new A();
a1.ID = 1;
Console.WriteLine(string.Format("Main a1.ID: /t{0}", a1.ID));
RefCall(ref a1);
Console.WriteLine(string.Format("Main a1.ID: /t{0}", a1.ID));
Console.WriteLine();
A a2 = new A();
a2.ID = 1;
Console.WriteLine(string.Format("Main a2.ID: /t{0}", a2.ID));
Call(a2);
Console.WriteLine(string.Format("Main a2.ID: /t{0}", a2.ID));
Console.Read();
}
static void RefCall(ref A a)
{
a.ID = 2;
Console.WriteLine(string.Format("RefCall a.ID: /t{0}", a.ID));
a = new A();
Console.WriteLine(string.Format("RefCall a.ID: /t{0}", a.ID));
}
static void Call(A a)
{
a.ID = 3;
Console.WriteLine(string.Format("Call a.ID: /t{0}", a.ID));
a = new A();
Console.WriteLine(string.Format("Call a.ID: /t{0}", a.ID));
}
}
class A
{
private int id = 0;
public int ID
{
get { return this.id; }
set { this.id = value; }
}
}
运行结果:
Main a1.ID: 1
RefCall a.ID: 2
RefCall a.ID: 0
Main a1.ID: 0
Main a2.ID: 1
RefCall a.ID: 3
RefCall a.ID: 0
Main a2.ID: 3
通过运行结果我们可以知道使用ref关键字传递参数的方法改变了Main函数中的变量(这里为a1),而不适用ref关键字的方法没有改变Main函数中的变量(这里为a2)。
至此我们就应该对引用类型使用和不使用ref关键的区别一目了然了。
ref关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。(摘自msdn)。
同时我们也可以在msdn上找到这样一段话:
按引用传递值类型(如本主题前面所示)是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。下面的示例显示出当引用类型作为 ref 参数传递时,可以更改对象本身。
理解:不使用ref关键字引用类型的参数传递的是该对象(记为对象A)的引用,即对象A位于托管堆中的地址。而使用ref关键字的引用类型的参数传递的是该对象(记为对象B)引用的引用,即保存对象B位于托管堆中地址的变量(该变量位于堆栈中)的引用。即ref传递的是堆栈地址,而引用(引用类型的引用)传递的是托管堆的地址。当将ref使用在引用类型上,传递的是保存引用类型对象堆地址的栈地址,而不是堆地址。
下面用一个例子来对比使用ref和不适用ref的区别
源代码:
class Program
{
static void Main(string[] args)
{
A a1 = new A();
a1.ID = 1;
Console.WriteLine(string.Format("Main a1.ID: /t{0}", a1.ID));
RefCall(ref a1);
Console.WriteLine(string.Format("Main a1.ID: /t{0}", a1.ID));
Console.WriteLine();
A a2 = new A();
a2.ID = 1;
Console.WriteLine(string.Format("Main a2.ID: /t{0}", a2.ID));
Call(a2);
Console.WriteLine(string.Format("Main a2.ID: /t{0}", a2.ID));
Console.Read();
}
static void RefCall(ref A a)
{
a.ID = 2;
Console.WriteLine(string.Format("RefCall a.ID: /t{0}", a.ID));
a = new A();
Console.WriteLine(string.Format("RefCall a.ID: /t{0}", a.ID));
}
static void Call(A a)
{
a.ID = 3;
Console.WriteLine(string.Format("Call a.ID: /t{0}", a.ID));
a = new A();
Console.WriteLine(string.Format("Call a.ID: /t{0}", a.ID));
}
}
class A
{
private int id = 0;
public int ID
{
get { return this.id; }
set { this.id = value; }
}
}
运行结果:
Main a1.ID: 1
RefCall a.ID: 2
RefCall a.ID: 0
Main a1.ID: 0
Main a2.ID: 1
RefCall a.ID: 3
RefCall a.ID: 0
Main a2.ID: 3
通过运行结果我们可以知道使用ref关键字传递参数的方法改变了Main函数中的变量(这里为a1),而不适用ref关键字的方法没有改变Main函数中的变量(这里为a2)。
至此我们就应该对引用类型使用和不使用ref关键的区别一目了然了。
相关文章推荐
- ref和out的区别,值类型和引用类型的使用
- C#中引用参数ref 、out的使用区别
- 类类型作为方法的参数时,使用 ref 和不使用ref的区别?
- C#中引用类型做方法参数时,加ref或out,与不加ref或out到底有什么区别?
- C#引用类型参数加ref或out与不加ref或out的区别
- 反射中使用值类型与引用类型的参数的区别
- C#中参数为引用类型加ref和不加的区别
- java 引用类型作为方法参数使用问题
- 拷贝构造函数的参数为什么必须使用引用类型
- 动态使用webservice,以及含有ref类型的参数的问题
- C++建立单向链表链表头指针需要使用指针类型的引用参数?
- Emit学习-答疑篇-值类型和引用类型在使用时的区别
- 拷贝构造函数的参数为什么必须使用引用类型——避免拷贝死循环
- 引用传递的参数类型,加不加ref是不同的 .
- C# 值类型 引用类型 作为参数传递区别
- C#中ref、out类型参数的区别和params类型参数的用法
- 参数类型ref、in与out的区别
- 拷贝构造函数的参数为什么必须使用引用类型
- 拷贝构造函数的参数为什么必须使用引用类型
- 值类型与引用类型(特殊的string) Typeof和GetType() 静态和非静态使用 参数传递 相关知识