什么时候会需要使用ref和out有时,我们会需要获取某个值在方法中的运行状态,根据定义的方法,我们仅仅能够获得一个返回值,但是,有时我们也许想获取多个值,通过返回值就不能返回这样的信息,我们可以通过在参数前使用ref或out,以得到多个返回值. 在执行Sql存储过程时,我们可以通过sql语句在存储过程中的运行状态,返回相应的值.sql的return只支持Int格式的返回值,通过使用ref或out我们就可以获取多个返回值,并提示给页面ref和out有什么区别:
当方法中的代码运行时,需要用到该参数,并且通过该参数返回所需要的值时,我们就需要使用ref.
如果仅仅是为了获取多个返回值,而方法中又不需要使用这些参数时,我们可以使用out.
示例
例1:在asp.net页面使用ref和out
protected void Page_Load(object sender, EventArgs e)
{
string str1, str2, s1 = "第一个参数", s2 = "第二个参数"; //运行下面一行代码,会提示以下错误: // 使用了未赋值的局部变量“str1” //UseRef(ref str1, ref str2); //输出结果: // 使用out的第一个参数 // 使用out的第二个参数
UseOut(out str1, out str2);
Response.Write(str1 + "<br/>");
Response.Write(str2 + "<br/>"); //输出结果: // 第一个参数使用ref // 第二个参数使用ref
UseRef(ref s1, ref s2);
Response.Write(s1 + "<br/>");
Response.Write(s2 + "<br/>");
}
public void UseOut(out string str1, out string str2)
{
str1 = "使用out的第一个参数";
str2 = "使用out的第二个参数";
}
public void UseRef(ref string s1, ref string s2)
{
s1 += "使用ref";
s2 += "使用ref";
}
例2:在存储过程中的参数使用output关键字时,对应到c#代码中,则是ref和out.
ref和out与output关系如下:
| ParameterDirection取值 |
描述 |
对应C# |
对应SQL |
| Input |
输入 |
|
|
| InputOutput |
输入输出 |
ref |
对应output |
| Output |
输出 |
out |
| ReturnValue |
返回值 |
|
|
开始例子:
建立Employee表:

表内数据如下:

建立存储过程如下:
ALTER PROCEDURE dbo.InsertEmployee
( @EmployeeName nvarchar(20),
@EmployeeAge int=null,
@EmployeeDepartmentID int=null,
@EmployeeScore int=null,
@outValue nvarchar(20) output )
AS
/* SET NOCOUNT ON */
if exists(
select *
from Employee
where EmployeeName=@EmployeeName)
begin set @outValue=
'用户名'+@EmployeeName+
'重复!'
return end insert into Employee (EmployeeName,EmployeeAge,EmployeeDeparmentID,EmployeeScore)
values (@EmployeeName,@EmployeeAge,@EmployeeDepartmentID,@EmployeeScore)
set @outValue=
'用户'+@EmployeeName+
'建立成功!'
return
页面代码如下:
string connectionString = ConfigurationManager.ConnectionStrings["dbstconnectionstring"].ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "InsertEmployee";
cmd.Parameters.AddWithValue("@EmployeeName", "宋八");
cmd.Parameters.AddWithValue("@EmployeeAge", 20);
cmd.Parameters.AddWithValue("@EmployeeDepartmentID", 1);
cmd.Parameters.AddWithValue("@EmployeeScore", 95);
//注意param_outValue.Direction // 设置param_outValue.Direction=Output,参数只需被声明即可// 对应数据库中output //SqlParameter param_outValue = new SqlParameter("@outValue", SqlDbType.NVarChar, 20); //param_outValue.Direction = ParameterDirection.Output; //cmd.Parameters.Add(param_outValue); //注意param_outValue.Direction // 设置为param_outValue.Direction=InputOutput,参数需要被初始化// 对应数据库中output
SqlParameter param_outValue = new SqlParameter("@outValue", SqlDbType.NVarChar,20); param_outValue.Direction = ParameterDirection.InputOutput; param_outValue.Value = string.Empty; cmd.Parameters.Add(param_outValue); conn.Open();cmd.ExecuteNonQuery(); conn.Close();Response.Write(param_outValue.Value);
第一次运行输出结果:
用户宋八建立成功!
第二次运行输出结果:
用户名宋八重复!
C#中关键字ref与out的区别
|
在C#中,ref与out是很特殊的两个关键字。使用它们,可以使参数按照引用来传递。 总的来说,通常我们向方法中传递的是值.方法获得的是这些值的一个拷贝,然后使用这些拷贝,当方法运行完毕后,这些拷贝将被丢弃,而原来的值不将受到影响.此外我们还有其他向方法传递参数的形式,引用(ref)和输出(out). 有时,我们需要改变原来变量中的值,这时,我们可以向方法传递变量的引用,而不是变量的值.引用是一个变量,他可以访问原来变量的值,修改引用将修改原来变量的值.变量的值存储在内存中,可以创建一个引用,他指向变量在内存中的位置.当引用被修改时,修改的是内存中的值,因此变量的值可以将被修改.当我们调用一个含有引用参数的方法时,方法中的参数将指向被传递给方法的相应变量,因此,我们会明白,为什么当修改参数变量的修改也将导致原来变量的值. 通俗的从功能上来讲,使用这两个关键字,可以使一个方法返回多个参数。 MSDN中的定义: ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。 out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。 |
首先,我们来看一个简单的例子:
static void TestRefAndOut()
{
string s1 = "Good Luck!";
TestRef(ref s1);
Console.WriteLine(s1);//output: Hello World!
}
static void TestRef(ref string str)
{
str = "Hello World!";
}
在TestRefAndOut()中将字符串s1以ref关键字的方式传到方法TestRef(ref string str)中,在这个方法中,我们改变了s1的引用变量str的值,最后,回到TestRefAndOut()方法后输出s1的值,发现其值已被改变。
将上例中的ref换成out,代码如下:
static void TestRefAndOut()
{
string s1 = "Good Luck!";
//TestRef(ref s1);
TestOut(out s1);
Console.WriteLine(s1);//output: Hello World!
}
static void TestOut(out string str)
{
str = "Hello World!";
}
同样,在将ref换成out后,会发现最后的输出仍然是相同的,那这两个关键字的区别是什么呢?
进一步测试:
ref:
static void TestRefAndOut()
{
string s1 = "Good Luck!";
TestRef(ref s1);
}
static void TestRef(ref string str)
{
Console.WriteLine(str);//output: Good Lick!
}
out
static void TestRefAndOut()
{
string s1 = "Good Luck!";
TestOut(out s1);
}
static void TestOut(out string str)
{
Console.WriteLine(str);//compile does not pass
}
ref的那段代码顺利编译,输出"Good Luck!",而out那段代码却无法通过编译,提示“Use of unassigned out parameter 'str'”,即使用了未分配地址的out参数str。怎么回事呢?
原来out参数在进入方法的时候,C#会自动清空它的一切引用和指向,所以在上面的out例子中,必需先要为str参数赋值。如以下程序。
static void TestRefAndOut()
{
string s1 = "Good Luck!";
TestOut(out s1);
}
static void TestOut(out string str)
{
str = "Hello World!";
Console.WriteLine(str);//output: Hello World!
}
Ok,得到第一个区别: out 参数在进入方法(函数)时后清空自己,使自己变成一个干净的参数,也因为这个原因必须在方法返回之前或再使用out参数前为 out 参数赋值(只有地址没有值的参数是不能被.net接受的);而ref参数是不需要在被调用方法使用前先赋值的,甚至也可以被调用方法中不改变ref参数的值,这都不会引起编译错误。
在继续看一段代码:
ref:
static void TestRefAndOut()
{
string s1;
TestRef(ref s1);
Console.WriteLine(s1);//compile does not pass!
}
static void TestRef(ref string str)
{
str = Hello World!";
}
out:
static void TestRefAndOut()
{
string s1;
TestOut(out s1);
Console.WriteLine(s1);//output: Hello World!
}
static void TestOut(out string str)
{
str = "Hello World!";
}
这回发现,ref这段代码无法编译了,s1是一个空引用,所以无法使用。而out参数则因为上述的那个原因,它不在乎s1是不是空引用,因为就算s1不是空引用,它也会把s1变成空引用的。Ok,第二个区别:ref参数在使用前必需初始化,而out不需要。嗯,由上边两个区别可以引申一下,out参数只进不出,ref参数有进有出。在用法上概括一下就是:out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。