我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:
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)
我应该用哪个,为什么?
当前回答
创作时间:
我们创建调用方法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)在堆上创建一个对象,并将其起始地址存储在参数变量中。不会抛出任何未初始化的错误,并且之前存储的任何引用都将丢失。
其他回答
注意,在函数内部传递的引用参数是直接处理的。
例如,
public class MyClass
{
public string Name { get; set; }
}
public void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = "Dog";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes "Dog".
}
public void Bar(MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = "Cat";
someObject = myTempObject;
}
这会写狗,而不是猫。因此,您应该直接在someObject上工作。
Ref表示Ref参数中的值已经设置,方法可以读取和修改它。 使用ref关键字等同于说调用方负责初始化形参的值。
Out告诉编译器,对象的初始化是由 函数需要赋值给out形参。 没有分配是不允许的。
https://www.codemaggot.com/ref-and-out-keywords/
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);
裁判上场又出局。
您应该优先使用out,只要它能满足您的需求。
我可能不太擅长这一点,但肯定字符串(即使他们在技术上是引用类型和生活在堆上)是通过值传递,而不是引用?
string a = "Hello";
string b = "goodbye";
b = a; //attempt to make b point to a, won't work.
a = "testing";
Console.WriteLine(b); //this will produce "hello", NOT "testing"!!!!
这就是为什么你需要引用,如果你想要改变存在于函数的作用域之外,否则你不传递引用。
据我所知,你只需要引用结构/值类型和字符串本身,因为字符串是一个引用类型,假装它是,但不是一个值类型。
我可能完全错了,我是新来的。