参考和输出参数问题 [重复]
Posted
技术标签:
【中文标题】参考和输出参数问题 [重复]【英文标题】:Ref and Out Parameters Questions [duplicate] 【发布时间】:2015-08-06 09:53:42 【问题描述】:我以为我理解其中的区别,但现在我不太确定。我已经多次阅读技术答案,但我不明白发生了什么。我有这个例子。
class Program
static void Main()
int val = 0;
Example1(val);
Console.WriteLine(val); // Still 0!
Example2(ref val);
Console.WriteLine(val); // Now 2!
Example3(out val);
Console.WriteLine(val); // Now 3!
static void Example1(int value)
value = 1;
static void Example2(ref int value)
value = 2;
static void Example3(out int value)
value = 3;
我一直认为默认参数的区别在于,如果我将val传递给Example1,我就不能使用赋值。
但是使用 ref 关键字 val 仍然为 0,但我创建了一个引用,现在它被视为 Example2(ref val) 中的变量“值”。到目前为止,我是否对任何事情感到困惑?如果我用过
int value = 0;
Example1(value);
Console.WriteLine(value); // this would then return 1 correct?
那么,out 关键字发生了什么?和 ref 一样吗?
【问题讨论】:
“默认参数”是什么意思?你的意思是当ref
或out
没有被使用?
@JohnSaunders 是的,当不使用 ref 和 out 时。我希望它是重复的,我已经多次阅读该帖子。我还是不明白。
您的最后一个代码块“如果我使用过..”正是您在第一个代码块中 Main
函数的前 3 行所做的。
我认为它是重复的,你只是不明白。你没有得到什么?请注意,传递值类型(如int
)和传递引用类型(如类的实例)之间有些不同。
顺便说一句,请停止使用“默认参数”一词。这与 public void Method(int val = 1)
的 C# 用法太接近了,如果您想传递 1
,则不必传递 val
。
【参考方案1】:
看看这是否有帮助:
没有“装饰器”
static void Example(int value)
Console.WriteLine("Value is 0", value);
value = 99;
usage
int value = 10;
Example(notADefaultValue); // Will print <Value is 10>
Console.WriteLine("Value is 0", value); // will print <Value is 10>
总结:默认情况下,值类型(structs/enums/int/double/etc)不作为引用传入,因此无论您对方法中的变量做什么都不会影响调用者。因此,“ref”关键字。如果您将引用类型传递给方法(即类)并更改其内部结构,这些将影响调用者。
默认参数:
static void Example(int value = 5)
Console.WriteLine("Value is 0", value);
usage
int notADefaultValue = 10;
Example(notADefaultValue); // Will print <Value is 10>
Example(); // will print <Value is 5>
总结:默认值允许你调用一个方法而不需要显式传递参数,使用默认值。
参考参数:
static void Example(ref int value)
Console.WriteLine("Value is 0", value);
value = 99;
usage
int value = 10;
Example(ref value); // Will print <Value is 10>
Console.WriteLine("Value is 0", value); // Will print <Value is 99>
总结:如果您将值类型作为 ref(引用)传递,则值本身会发生变化。默认情况下,所有引用类型都作为 ref 传入。仅供参考,int 是原始类型,因此需要显式的“ref”。
输出参数:
static void Example(out int value)
value = 99;
Console.WriteLine("Value is 0", value);
usage
int value; // no need to init it
Example(out value); // Will print <Value is 99>
Console.WriteLine("Value is 0", value); // Will print <Value is 99>
总结:输出参数类似于返回变量,但通过方法的签名传入。最常见的示例是 TryParse,其中该方法返回重要信息,并根据该信息输出参数是否有效(如果为真则有效)。
【讨论】:
OP 错误地使用了术语“默认参数”。他实际上只是指“既不使用ref
也不使用out
的参数”。
没关系,解释默认值并没有什么坏处。我已经编辑了答案以包含“既不使用 ref 也不使用 out 的参数”
漂亮,如果没有你们两个@JohnSaunders,我无法弄清楚。【参考方案2】:
在第一个示例中,您没有指定变量是引用,因为它是基本类型,所以它只是复制提供的数字。所以value
里面Example1
是value
里面Main
的一个副本。
第二个示例使用引用。这意味着函数 Example2
和 Main
内部都指向内存中的同一位置,因此在进入和退出函数时都会传输值。
在第三个示例中,out
关键字的作用与第二个相同,只是在输入函数时初始化为 0。结果,它只是返回某种数据的参数。该值只是在退出函数时传递。
【讨论】:
您将ref
与引用类型混淆了。
@JohnSaunders 基本类型默认通过值传递,所有其他类型通过引用传递。 ref
只是一种明确告诉它通过引用传递的方式。
不,请看“Types (C# Programming Guide)”。
"不要把引用传递的概念和引用类型的概念混为一谈,这两个概念是不一样的。一个方法参数可以通过ref来修改,不管是值类型还是引用类型。值类型通过引用传递时没有装箱。"
“通过引用传递”并不意味着“变量是引用”。【参考方案3】:
好的,它与 cmets 中的链接问题重复,但我会尽力为您解释。
未修饰的参数
案例A:public void MyFunc(int x)
-或-
案例B:public void MyFunc(MyClass y)
在情况 A 中,参数是值类型,默认情况下,值类型作为原始值的副本传递给函数。这并不意味着您不能修改该值,但该值不会反映在调用位置。这对于所有值类型都是一样的,值在传递给函数之前被复制。
在案例 B 中,参数是引用类型。这些类型默认按原样传递。它们不会被复制,但您不能更改引用(通过为类型分配 new
或 null
值)。您可以更改对象的内容(其中的任何属性/字段),它将反映在调用位置。
ref 关键字
案例A:public void MyFunc(ref int x)
-或-
案例B:public void MyFunc(ref MyClass x)
在情况 A 中,您告诉编译器您要通过引用传递值,这意味着编译器不会复制该类型,而是传递对该类型的引用。允许函数改变它。
在情况 B,您告诉编译器函数 是 允许更改引用指向的位置(您可以创建 new
或将其设置为 null
,它将是反映在调用站点中。
out 关键字
案例A:public void MyFunc(out int x)
-或-
案例B:public void MyFunc(out MyClass x)
在这里,您基本上是在为函数定义额外的返回类型。它的方法参数告诉调用者在x
变量的位置期待一个结果。这对两者都是一样的。在任何情况下,调用者都不应该期望 x
之前的任何值在之后都相同。事实上,您可以预期它不会相同,因为该方法需要在允许返回之前为 x 分配一个新值。
out
基本上意味着您为返回值提供了一个位置,对于值类型,只需使用默认构造函数,对于引用类型,在传入之前将值初始化为 null
。
【讨论】:
以上是关于参考和输出参数问题 [重复]的主要内容,如果未能解决你的问题,请参考以下文章