按值传递表示传递参数的副本。 对该副本的更改不会更改原始文件。
通过引用传递意味着传递对原始的引用。 对引用的更改会影响原始引用。
REF告诉编译器在进入函数之前初始化对象。 REF表示该值已经设置,因此该方法可以读取并修改它。 REF有两种方式,包括进出。
OUT告诉编译器该对象将在函数内初始化。 OUT表示该值尚未设置,因此必须在调用return之前设置。 OUT只是一种方式,即出局。
那么在什么情况下你会结合使用ref和out关键字,通过引用传递还是通过值传递? 例子会有很大帮助。
非常感谢。
答案 0 :(得分:16)
您将从不将ref
和out
合并到1个参数上。它们都意味着“通过引用传递”。
您当然可以在一个方法中组合ref参数和out参数。
ref
和out
之间的差异主要在于意图。 ref信号2路数据传输,out表示1路。
但除了意图之外,C#编译器跟踪明确赋值,这是最显着的差异。它还可以防止误读(读取)out参数。
void SetOne(out int x)
{
int y = x + 1; // error, 'x' not definitely assigned.
x = 1; // mandatory to assign something
}
void AddTwo(ref int x)
{
x = x + 2; // OK, x is known to be assigned
}
void Main()
{
int foo, bar;
SetOne(out foo); // OK, foo does not have to be assigned
AddTwo(ref foo); // OK, foo assigned by SetOne
AddTwo(ref bar); // error, bar is unassigned
}
答案 1 :(得分:8)
非常感谢
通过正确和谨慎地使用语言,您的理解将得到改善。
按值传递表示传递参数的副本。
是的,这完全准确。
对该副本的更改不会更改原件。
不完全是。首先要仔细区分值和变量。考虑:
class Foo { public int x; }
...
void N()
{
Foo blah = new Foo();
blah.x = 0;
M(blah);
}
...
void M(Foo foo)
{
foo.x = 123; // changes blah.x
foo = null; // does not change blah
}
这里的变量是x,blah和foo。 x是一个字段,blah是本地的,foo是一个形式参数。
此处的值为null,0,123,以及对Foo实例的引用。 该引用是一个值。了解这一事实至关重要。
通过将变量blah的值复制到变量foo中来传递blah值的副本。 blah的值是对Foo实例的引用。
M可以改变变量x的值,因为M有一个blah值的副本,它是对Foo的引用。当M将foo的内容更改为null时,这不会改变blah; foo包含blah值的副本。
通过引用传递意味着传递对原始的引用。
仔细选择措辞。什么是“原始”?
这将更好地说明为“通过引用传递意味着传递对参数的引用,该参数必须是变量”。考虑它的一种更简单的方法是“通过引用传递使参数成为作为参数传递的变量的别名”。
对参考的更改会影响原件。
由于参数和参数是彼此的别名,因此引用的更改不会影响原始参数;参考文献是原文。它们都是相同的变量。
REF告诉编译器在进入函数之前初始化对象。
“对象”毫无意义。你的意思是“变量”。
“ref”不“告诉编译器变量已初始化”。相反,“ref”告诉编译器“你,编译器,必须验证变量是否已初始化”。那是完全不同的!
REF表示已设置值
不,ref要求已设置变量。没有“设定价值”这样的东西。
因此,该方法可以读取并修改它。
“it”的意思是“变量”。
REF有两种方式,包括进出。
正确。
OUT告诉编译器该对象将在函数内初始化。
停止使用“对象”来表示“变量”。如果你不再混淆完全不同的东西,你会更清楚地理解事情。 变量不是对象。变量是存储位置,其中一些可能包含值,其中一些值可能是对象的引用
因此,out告诉编译器该变量将在方法内初始化,是的,但这不太对。您忘记了方法将引发异常的情况,或者方法将进入无限循环 - 这些也是合法的方案。
OUT表示尚未设置值
同样,“值”是指“变量”。但这不准确。将初始化变量作为“out”参数传递是完全合法的。毫无意义,但合法。
因此必须在调用return之前设置。
没有调用“return”;方法被称为。但是,是的,该方法必须在正常返回之前为变量赋值。
OUT只是一种方式,即出局。
右。
那么在什么情况下你会结合使用ref和out关键字
没有这样的场景。
答案 2 :(得分:1)
编辑:我已经更正了这个答案,以反映C#中的'out'关键字没有达到预期效果(例如计算机科学意义上的真正OUT参数) )。我最初表示'out'是通过值OUT传递但被证明是错误的。
你不能同时使用'out'和'ref'。 C#(.NET Framework)中有三种调用约定:
C#没有真正的OUT或IN-OUT参数能力。
要查看C#中的'out'参数不是真的OUT参数,可以使用以下代码:
public class Test
{
Action _showValue;
public void Run()
{
string local = "Initial";
_showValue = () => { Console.WriteLine(local.ToString()); };
Console.WriteLine("Passing by value");
inMethod(local);
Console.WriteLine("Passing by reference with 'out' keyword");
outMethod(out local);
Console.WriteLine("Passing by reference with 'ref' keyword");
refMethod(ref local);
}
void inMethod(string arg)
{
_showValue();
arg = "IN";
_showValue();
}
void outMethod(out string arg)
{
_showValue();
arg = "OUT";
_showValue();
}
void refMethod(ref string arg)
{
_showValue();
arg = "REF";
_showValue();
}
}
输出结果为:
Passing by value
Initial
Initial
Passing by reference with 'out' keyword
Initial
OUT
Passing by reference with 'ref' keyword
OUT
REF
正如您所看到的,'out'和'ref'实际上都通过了REF。唯一的区别在于编译器如何将它们视为明确的赋值目的。
答案 3 :(得分:1)
你了解通过任何一种方式的动态。一些参数场景可能是:
ref int num
表示输入/输出参数。函数可以修改其中的值。out int num
和ref一样,除了函数必须在返回之前为它赋值。通常,输出参数适用于函数必须返回多个值时,因为函数只有一个返回值(尽管它可以是复合值)。
有时,数据访问提供程序(如某些ADO.NET方法)使用输出参数来传递信息。一些数据访问方法模仿具有输入/输出参数的数据库存储过程。
编辑:参考类型的一个规定是参数ref StringBuilder word
或StringBuilder word
(按值)行为相同 - 外部字符串受到影响,尽管底层函数可能略有不同,因为此时焦点是参考而不是堆上的值。
答案 4 :(得分:0)
你通过ref传递你想要被另一个函数读取和写入的东西,所以你应该传递初始化的变量才能被正确读取。
编辑:示例:
void mymethod(ref int a) {
a++;
}
你传递的东西是你想要被另一个函数写的东西,但你不需要初始化它,因为它不会被函数读取,只能写入。
编辑:示例:
void mymethod2(out string a) {
a="hello";
}
答案 5 :(得分:0)
如果您有一个需要返回多个值的方法,则使用OUT
关键字非常有用。例如,查看int.TryParse()
等方法。
使用REF
更多是为了显示对象。请记住,传入方法的任何非原语都是通过引用传递的,在普通的托管代码中并不需要它。通过声明REF关键字,您声明参数可能会在方法体中被修改,因此调用代码应该知道它(因此您必须在调用代码中明确添加ref
的原因同样。
答案 6 :(得分:0)
如果您了解c ++,这可能会对您有所帮助:
void Foo(Bar) {} // pass by value c# (if it's a value type ;))
void Foo(Bar) {} // c++
void Foo(Bar) {} // pass by reference c# (if it's a reference type ;))
void Foo(Bar&) {} // c++
void Foo(ref Bar) {} // c#
void Foo(Bar*) // c++
void Foo(out Bar) {} // c#
void Foo(Bar**) {} // c++ (the contents of *Bar needs to be filled up)