我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:
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)
我应该用哪个,为什么?
当前回答
扩展狗和猫的例子。带有ref的第二个方法更改调用者引用的对象。所以叫“猫”!!
public static void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = "Dog";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes "Dog".
Bar(ref myObject);
Console.WriteLine(myObject.Name); // Writes "Cat".
}
public static void Bar(MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = "Cat";
someObject = myTempObject;
}
public static void Bar(ref MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = "Cat";
someObject = myTempObject;
}
其他回答
From the standpoint of a method which receives a parameter, the difference between ref and out is that C# requires that methods must write to every out parameter before returning, and must not do anything with such a parameter, other than passing it as an out parameter or writing to it, until it has been either passed as an out parameter to another method or written directly. Note that some other languages do not impose such requirements; a virtual or interface method which is declared in C# with an out parameter may be overridden in another language which does not impose any special restrictions on such parameters.
从调用者的角度来看,c#在很多情况下假设调用带有out形参的方法时,会导致传入的变量在未被读取之前就被写入。当调用用其他语言编写的方法时,这个假设可能不正确。例如:
struct MyStruct
{
...
myStruct(IDictionary<int, MyStruct> d)
{
d.TryGetValue(23, out this);
}
}
如果myDictionary标识了一个用c#以外的语言编写的dictionary <TKey,TValue>实现,即使MyStruct s = new MyStruct(myDictionary);看起来像一个任务,它可能会留下未修改的s。
注意用VB编写的构造函数。NET与c#中的方法不同,它不假设被调用的方法是否会修改任何out参数,并且无条件地清除所有字段。上面提到的奇怪行为不会发生在完全用VB或完全用c#编写的代码中,但是当用c#编写的代码调用用VB.NET编写的方法时就会发生。
ref修饰符的意思是:
该值已经设置,并且 该方法可以读取和修改它。
out修饰符的意思是:
Value未被设置,并且在设置之前不能被方法读取。 方法必须在返回之前设置它。
简洁的回答。
ref和out关键字都用于引用传递。 关键字为ref的变量必须有一个值或必须引用一个对象 或者在它传递之前为null。 与ref不同,关键字为out的变量必须有一个值或必须 在对象传递后引用对象或null以及不需要 在传递之前有一个值或引用一个对象。
我可能不太擅长这一点,但肯定字符串(即使他们在技术上是引用类型和生活在堆上)是通过值传递,而不是引用?
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"!!!!
这就是为什么你需要引用,如果你想要改变存在于函数的作用域之外,否则你不传递引用。
据我所知,你只需要引用结构/值类型和字符串本身,因为字符串是一个引用类型,假装它是,但不是一个值类型。
我可能完全错了,我是新来的。
为了说明这些优秀的解释,我开发了以下控制台应用程序:
using System;
using System.Collections.Generic;
namespace CSharpDemos
{
class Program
{
static void Main(string[] args)
{
List<string> StringList = new List<string> { "Hello" };
List<string> StringListRef = new List<string> { "Hallo" };
AppendWorld(StringList);
Console.WriteLine(StringList[0] + StringList[1]);
HalloWelt(ref StringListRef);
Console.WriteLine(StringListRef[0] + StringListRef[1]);
CiaoMondo(out List<string> StringListOut);
Console.WriteLine(StringListOut[0] + StringListOut[1]);
}
static void AppendWorld(List<string> LiStri)
{
LiStri.Add(" World!");
LiStri = new List<string> { "¡Hola", " Mundo!" };
Console.WriteLine(LiStri[0] + LiStri[1]);
}
static void HalloWelt(ref List<string> LiStriRef)
{ LiStriRef = new List<string> { LiStriRef[0], " Welt!" }; }
static void CiaoMondo(out List<string> LiStriOut)
{ LiStriOut = new List<string> { "Ciao", " Mondo!" }; }
}
}
/*Output:
¡Hola Mundo!
Hello World!
Hallo Welt!
Ciao Mondo!
*/
AppendWorld: A copy of StringList named LiStri is passed. At the start of the method, this copy references the original list and therefore can be used to modify this list. Later LiStri references another List<string> object inside the method which doesn't affect the original list. HalloWelt: LiStriRef is an alias of the already initialized ListStringRef. The passed List<string> object is used to initialize a new one, therefore ref was necessary. CiaoMondo: LiStriOut is an alias of ListStringOut and must be initialized.
因此,如果一个方法只是修改了被传递的变量引用的对象,编译器不会让你使用out,你也不应该使用ref,因为它不仅会让编译器困惑,而且会让代码的读者困惑。如果该方法将使传递的参数引用另一个对象,则对于已经初始化的对象使用ref,对于必须为传递的参数初始化新对象的方法使用out。除此之外,ref和out的行为是一样的。