Ref和Out参数问题
本文关键字:问题 参数 Out Ref | 更新日期: 2023-09-27 17:50:32
我原以为我了解其中的区别,但现在我不那么确定了。我已经读了好几遍技术答案,但我不明白发生了什么。我有这个例子。
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)中的变量"值"。到目前为止,我是不是被什么事缠住了?如果我用了
int value = 0;
Example1(value);
Console.WriteLine(value); // this would then return 1 correct?
现在,out关键字发生了什么?和ref一样吗?
看看是否有帮助:
不"修饰符"
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/enum/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>
}
总结:默认值允许你调用一个方法,而不需要显式地传递参数,使用默认值。
Ref参数:
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>
}
Summary: Out形参类似于返回变量,但通过方法的签名传递进来。最常见的例子是TryParse,该方法返回重要信息,并根据该信息确定out参数是否有效(如果为真则有效)。
在第一个示例中,您没有指定变量是引用,因为它是基本类型,所以它只是复制提供的数字。因此,Example1
中的value
是Main
中value
的复制。
第二个例子使用引用。这意味着函数Example2
内部和Main
内部都指向内存中的同一位置,因此当进入和退出函数时,值被传输。
在第三个示例中,out
关键字的作用与第二个关键字相同,只是在进入函数时将其初始化为0。因此,它只是返回某种数据的参数。
好的,这是评论中链接问题的重复,但我会尽力为你解释的。
<<p> 简朴的参数/strong>案例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
,它将反映在调用站点中。
输出关键词
案例A: public void MyFunc(out int x) { }
或者
案例B: public void MyFunc(out MyClass x) { }
在这里,您基本上是在为函数定义额外的返回类型。它是方法参数,告诉调用者期望在x
变量的位置得到一个结果。这对两者都是一样的。在任何情况下,调用者都不应该期望x
之前的任何值在之后都会相同。实际上,您可以预期它将不相同,因为该方法需要在允许返回之前为x分配一个新值。
out
基本上意味着你为返回值提供了一个位置,对于值类型只使用默认构造函数,对于引用类型,在传递它之前将值初始化为null
。