没有指明ref或者out的,就是按值传递
返回值没地方指明ref或者out,所以肯定是按值传递
但是要搞清楚这里的“值”是什么意思
一个变量保存一个值。如果这个变量的类型是“值类型”(ValueType,包括所有基础数据型和结构型),它保存的值就是真正的数据;如果这个变量的类型是“引用类型”,它保存的值就是一个地址,在内存的这个地址里能找到对象的具体数值。
这么说可能就搞糊涂了,我具体化一点。
DataSet a = ...;
B(a);
void B(DataSet ds) {
ds.Tables[0].Rows[0][0] = "123"; //1
ds = new DataSet(); //2
}
上面的例子里,参数没有ref/out,所以是按值传递。但是当主程序调用 B(a) 的时候,按值传递传了什么东西?——引用类型,传了 a 所指的 DataSet 对象的地址。于是,主程序的 a 和 B 方法里的 ds,引用的是同一个对象,于是第一行对 ds 的改动,主程序的 a 也相应的被改动了。但是方法 B 的第二行,将 ds 赋予另一个 DataSet 的地址。结果是 ds 的值变了,但是 a 的值没变,a 仍然指着原先的 DataSet。
再来看另一个例子。
DataSet a = ...;
B(ref a);
void B(ref DataSet ds) {
ds.Tables[0].Rows[0][0] = "123"; //1
ds = new DataSet(); //2
}
现在,参数指定是按引用传递。这是什么效果?a 和 ds 变成是同一个东西,不但所指的 DataSet 是同一个 DataSet(值相同),他们本身的地址也相同。于是,方法第一行对 DataSet 对象的改动,和方法第二行对变量值的改动,都返回给主程序了,也就是方法执行之后,a 也指向了一个新的 DataSet。
最后来看“返回值”。
DataSet a = B();
DataSet B() {
DataSet ds = new DataSet(); //1
ds.Tables[0].Rows[0][0] = "123";
return ds; //2
}
上例里,主程序先为 a 分配了内存并且指定它的数据类型为 DataSet,然后调用方法 B。方法 B 里为 ds 分配了内存并且指定其类型为 DataSet——这样说,很明显 a 和 ds 是不同的两个变量了。然后第2行返回 ds。我开头说过了,因为返回值没有而且无法指定ref或者out,所以它只能是值类型,也就是说,return ds; 返回的是 ds 的值。ds 的值是什么?是一个地址,这个地址指向一个刚刚创建的 DataSet。返回之后,变量 a 就赋予了这个值,也就是指向刚才那个 DataSet 的地址,于是整个故事只存在一个 DataSet 对象,但是,存在两个不同的变量,a 和 ds。
说到这里,总结一下。你的猜测:“如果是按照值返回
那么一般我们在函数调用的时候应该传个引用dataSet类型,这样效率高些”不对了,因为你认为引用类型的值就是具体的对象,所以才有这个想法。
ps,如果你学过C或者C++,对指针有印象的话,去翻翻MSDN,看看他们对一些使用ref参数的方法的C++定义。一个形如 void B(ref DataSet ds) 的方法,C++定义里的参数是(DataSet** ds),而不是简单的(DataSet* ds),因为方法需要写入‘保存“保存DataSet的地址”的地址’。
返回值没地方指明ref或者out,所以肯定是按值传递
但是要搞清楚这里的“值”是什么意思
一个变量保存一个值。如果这个变量的类型是“值类型”(ValueType,包括所有基础数据型和结构型),它保存的值就是真正的数据;如果这个变量的类型是“引用类型”,它保存的值就是一个地址,在内存的这个地址里能找到对象的具体数值。
这么说可能就搞糊涂了,我具体化一点。
DataSet a = ...;
B(a);
void B(DataSet ds) {
ds.Tables[0].Rows[0][0] = "123"; //1
ds = new DataSet(); //2
}
上面的例子里,参数没有ref/out,所以是按值传递。但是当主程序调用 B(a) 的时候,按值传递传了什么东西?——引用类型,传了 a 所指的 DataSet 对象的地址。于是,主程序的 a 和 B 方法里的 ds,引用的是同一个对象,于是第一行对 ds 的改动,主程序的 a 也相应的被改动了。但是方法 B 的第二行,将 ds 赋予另一个 DataSet 的地址。结果是 ds 的值变了,但是 a 的值没变,a 仍然指着原先的 DataSet。
再来看另一个例子。
DataSet a = ...;
B(ref a);
void B(ref DataSet ds) {
ds.Tables[0].Rows[0][0] = "123"; //1
ds = new DataSet(); //2
}
现在,参数指定是按引用传递。这是什么效果?a 和 ds 变成是同一个东西,不但所指的 DataSet 是同一个 DataSet(值相同),他们本身的地址也相同。于是,方法第一行对 DataSet 对象的改动,和方法第二行对变量值的改动,都返回给主程序了,也就是方法执行之后,a 也指向了一个新的 DataSet。
最后来看“返回值”。
DataSet a = B();
DataSet B() {
DataSet ds = new DataSet(); //1
ds.Tables[0].Rows[0][0] = "123";
return ds; //2
}
上例里,主程序先为 a 分配了内存并且指定它的数据类型为 DataSet,然后调用方法 B。方法 B 里为 ds 分配了内存并且指定其类型为 DataSet——这样说,很明显 a 和 ds 是不同的两个变量了。然后第2行返回 ds。我开头说过了,因为返回值没有而且无法指定ref或者out,所以它只能是值类型,也就是说,return ds; 返回的是 ds 的值。ds 的值是什么?是一个地址,这个地址指向一个刚刚创建的 DataSet。返回之后,变量 a 就赋予了这个值,也就是指向刚才那个 DataSet 的地址,于是整个故事只存在一个 DataSet 对象,但是,存在两个不同的变量,a 和 ds。
说到这里,总结一下。你的猜测:“如果是按照值返回
那么一般我们在函数调用的时候应该传个引用dataSet类型,这样效率高些”不对了,因为你认为引用类型的值就是具体的对象,所以才有这个想法。
ps,如果你学过C或者C++,对指针有印象的话,去翻翻MSDN,看看他们对一些使用ref参数的方法的C++定义。一个形如 void B(ref DataSet ds) 的方法,C++定义里的参数是(DataSet** ds),而不是简单的(DataSet* ds),因为方法需要写入‘保存“保存DataSet的地址”的地址’。