我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:
public void myFunction(ref MyClass someClass)
and
public void myFunction(out MyClass someClass)
我应该用哪个,为什么?
我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:
public void myFunction(ref MyClass someClass)
and
public void myFunction(out MyClass someClass)
我应该用哪个,为什么?
当前回答
假设多姆因为TPS报告的备忘录出现在彼得的隔间里。
如果Dom是一个参考参数,他就会有一份备忘录的打印副本。
如果多姆是一个多余的论据,他会让彼得打印一份新的备忘录,让他随身携带。
其他回答
Ref告诉编译器对象在进入函数之前已经初始化,而out告诉编译器对象将在函数内部初始化。
所以当ref是双向的,out是唯一的。
裁判上场又出局。
您应该优先使用out,只要它能满足您的需求。
“贝克”
这是因为第一个将字符串引用更改为指向“Baker”。更改引用是可能的,因为您通过ref关键字传递了它(=>是对字符串引用的引用)。 第二个调用获取字符串引用的副本。
弦一开始看起来很特别。但字符串只是一个引用类,如果你定义
string s = "Able";
那么s是一个包含文本“Able”的字符串类的引用! 对同一个变量via的另一个赋值
s = "Baker";
不改变原来的字符串,但只是创建一个新的实例,让我们指向该实例!
你可以试试下面的小代码示例:
string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);
你想要什么? 您将得到的仍然是“Able”,因为您只是将s中的引用设置为另一个实例,而s2指向原始实例。
编辑: String也是不可变的,这意味着根本没有修改现有字符串实例的方法或属性(你可以尝试在文档中找到一个,但你找不到:-))。所有字符串操作方法都会返回一个新的字符串实例!(这就是为什么你在使用StringBuilder类时经常会得到更好的性能)
创作时间:
我们创建调用方法Main()
(2)它创建一个List对象(这是一个引用类型对象)并将其存储在变量myList中。
public sealed class Program
{
public static Main()
{
List<int> myList = new List<int>();
在运行时:
(3)运行时在堆栈#00处分配一个内存,足够宽来存储一个地址(#00 = myList,因为变量名实际上只是内存位置的别名)
(4)运行时在内存位置#FF的堆上创建一个列表对象(所有这些地址都是为了举例)
(5) Runtime会将对象的起始地址#FF存储在#00(或者在word中,将List对象的引用存储在指针myList中)
回到创作时间:
(6)然后我们将List对象作为参数myParamList传递给被调用的方法modifyMyList,并将一个新的List对象赋给它
List<int> myList = new List<int>();
List<int> newList = ModifyMyList(myList)
public List<int> ModifyMyList(List<int> myParamList){
myParamList = new List<int>();
return myParamList;
}
在运行时:
(7)运行时启动被调用方法的调用例程,作为它的一部分,检查参数的类型。
(8)在找到引用类型后,它在堆栈#04处分配一个内存,用于别名参数变量myParamList。
然后它将值#FF也存储在其中。
(10) Runtime在内存位置#004的堆上创建一个列表对象,并用这个值替换#04中的#FF(或者在这个方法中取消引用原始的list对象并指向新的list对象)
#00中的地址不会改变,并保留对#FF的引用(或者原始的myList指针不会被干扰)。
ref关键字是一个编译器指令,用于跳过(8)和(9)的运行时代码的生成,这意味着不会为方法参数分配堆。它将使用原始的#00指针对位于#FF的对象进行操作。如果原始指针没有初始化,运行时将停止抱怨它不能继续,因为变量没有初始化
out关键字是一个编译器指令,它与ref几乎相同,只是在(9)和(10)处略有修改。编译器期望参数是未初始化的,并将继续使用(8),(4)和(5)在堆上创建一个对象,并将其起始地址存储在参数变量中。不会抛出任何未初始化的错误,并且之前存储的任何引用都将丢失。
ref和out就像c++中传递引用和传递指针一样。
对于ref,参数必须声明并初始化。
对于out,实参必须声明,但可以初始化,也可以不初始化
double nbr = 6; // if not initialized we get error
double dd = doit.square(ref nbr);
double Half_nbr ; // fine as passed by out, but inside the calling method you initialize it
doit.math_routines(nbr, out Half_nbr);