类型介绍
在几乎所有的OOP语言中都存在种类型的值
值类型
引用类型
以C#为例其值类型为sbytebytecharshortushortintuintlong和ulongfloat和double当然还有decimal和bool而引用类型则是string和object
我想说的
我想说的就是——Ref和Out把我弄糊涂的原因是当时没有认真的去分析它对不同类型所做出的不同的动作
对于值类型
使用了Ref和Out的效果就几乎和C中使用了指针变量一样它能够让你直接对原数进行操作而不是对那个原数的Copy进行操作举个小例子
using System;namespace ConsoleApplication
{
/// <summary>
/// Class 的摘要说明
/// </summary>
class Class
{
/// <summary>
/// 应用程序的主入口点
/// </summary>
[STAThread]
static void Main(string[] args)
{
int a = ;
int b; squareRef(ref a);
squareOut(out b); ConsoleWriteLine(Thea in the Main is: + a);
ConsoleWriteLine(Theb in the Main is: + b);
}static void squareRef(ref int x)
{
x = x * x;
ConsoleWriteLine(The x in the squareRef is: + x);
}static void squareOut(out int y)
{
y = ;
y = y * y;
ConsoleWriteLine(The y in the squareOut is: + y);
}
}
}
显示的结果就是——
这样的话就达到了和C中的指针变量一样的作用
对于引用类型
对于引用类型就比较难理解了
先要了解到这一层——就是当一个方法接收到一个引用类型的变量的时候它将获得这个引用(Reference)的一个Copy由于Ref关键字可以用来向方法传递引用所以如果这个功能被误用了——比如当一个如数组类型的引用对象用关键字Ref传递的时候被调用的方法实际上已经控制了传递过来的引用本身这样将使得被调用方法能用不同的对象甚至NULL来代替调用者的原始引用!
如图内存地址为的变量arrayA中其实存放着数组{……}的内存起始地址如果一个方法fun()使用fun( arrayA[] )的话它将顺利的获得数据但这个将放在一个Copy中不会放到内存的位置而这个时候我们如果使用fun( ref arrayA[] )的话我们得到的值就是啦(也就是说被调用方法能够修改掉arrayA中的那个引用使之不再指向甚至可以用NULL来代替这样的话那个地址中的数据可能就要被垃圾回收机制清理了)
有个例子
using System;
using SystemDrawing;
using SystemCollections;
using SystemComponentModel;
using SystemWindowsForms;
using SystemData;
namespace RefOut
{
/// <summary>
/// Form 的摘要说明
/// </summary>
public class Form : SystemWindowsFormsForm
{
private SystemWindowsFormsButton button;
private SystemWindowsFormsLabel label;
/// <summary>
/// 必需的设计器变量
/// </summary>
private SystemComponentModelContainer components = null;
public Form()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
componentsDispose();
}
}
baseDispose( disposing );
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 不要使用代码编辑器修改
/// 此方法的内容
/// </summary>
private void InitializeComponent()
{
thisbutton = new SystemWindowsFormsButton();
thislabel = new SystemWindowsFormsLabel();
thisSuspendLayout();
//
// button
//
thisbuttonDock = SystemWindowsFormsDockStyleTop;
thisbuttonLocation = new SystemDrawingPoint( );
thisbuttonName = button;
thisbuttonSize = new SystemDrawingSize( );
;thisbuttonTabIndex = ;
thisbuttonText = 显示输出;
thisbuttonClick += new SystemEventHandler(thisbutton_Click);
//
// label
//
thislabelLocation = new SystemDrawingPoint( );
thislabelName = label;
thislabelSize = new SystemDrawingSize( );
thislabelTabIndex = ;
thislabelText = label;
//
// Form
//
thisAutoScaleBaseSize = new SystemDrawingSize( );
thisClientSize = new SystemDrawingSize( );
thisControlsAdd(thislabel);
thisControlsAdd(thisbutton);
thisMaximizeBox = false;
thisMinimizeBox = false;
thisName = Form;
thisText = Ref & Out;
thisResumeLayout(false);
}
#endregion
/// <summary>
/// 应用程序的主入口点
/// </summary>
[STAThread]
static void Main()
{
ApplicationRun(new Form());
}
private void button_Click(object sender SystemEventArgs e)
{
int[] firstArray = { };
int[] firstArrayCopy = firstArray;
thislabelText = Test Passing firstArray reference by value;
thislabelText += \n\nContents of firstArray before calling FirstDouble:\n\t;
for(int i = ;i < firstArrayLength; i++)
{
thislabelText += firstArray[i] + ;
}
FirstDouble(firstArray);
thislabelText += \n\nContents of firstArray after calling FirstDouble\n\t;
for(int i=;i<firstArrayLength;i++)
{
thislabelText += firstArray[i] + ;
}
if(firstArray == firstArrayCopy)
thislabelText +=\n\nThe references refer to the same array\n;
else
thislabelText +=\n\nThe reference refer to different arrays\n;
int[] secondArray = { };
int[] secondArrayCopy = secondArray;
thislabelText += \nTest passing secondArray reference by reference;
thislabelText += \n\nContents of secondArray before calling SecondDouble:\n\t;
for(int i=;i<secondArrayLength; i++)
{
thislabelText += secondArray[i] + ;
}
SecondDouble(ref secondArray);
thislabelText +=\n\nContents of secondArray after calling SecondDouble:\n\t;
for(int i=; i<secondArrayLength;i++)
{
thislabelText += secondArray[i] + ;
}
if(secondArray== secondArrayCopy)
thislabelText += \n\nThe reference refer to the same array;
else
thislabelText += \n\nThe reference refer to different arrays;
thislabelText += \n___________________heshi_________________\nsecondarray\n;
for(int i = ;i<secondArrayLength;i++)
{
thislabelText += secondArray[i] + ;
}
thislabelText +=\nsecondarraycopy\n;
for(int i=;i<secondArrayCopyLength;i++)
{
thislabelText += secondArrayCopy[i] + ;
}
}
void FirstDouble(int[] array)
{
for(int i = ;i<arrayLength;i++)
array[i] *= ;
array = new int[] { };
}
void SecondDouble(ref int[] array)
{
for(int i=;i<arrayLength;i++)
{
array[i] *= ;
}
array = new int[] { };
}
}
}
运行后的结果是
这个就说明了被调用的程序已经改变了原有的Reference
总结
总的说来Ref和Out这两个关键字都能够提供相似的功效其作用也很像C中的指针变量稍有不同之处是
使用Ref型参数时传入的参数必须先被初始化而Out则不需要对Out而言就必须在方法中对其完成初始化
使用Ref和Out时都必须注意在方法的参数和执行方法时都要加Ref或Out关键字以满足匹配
Out更适合用在需要Return多个返回值的地方而Ref则用在需要被调用的方法修改调用者的引用的时候