参考和输出参数问题 [重复]

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 一样吗?

【问题讨论】:

“默认参数”是什么意思?你的意思是当refout没有被使用? @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里面Example1value里面Main的一个副本。

第二个示例使用引用。这意味着函数 Example2Main 内部都指向内存中的同一位置,因此在进入和退出函数时都会传输值。

在第三个示例中,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 中,参数是引用类型。这些类型默认按原样传递。它们不会被复制,但您不能更改引用(通过为类型分配 newnull 值)。您可以更改对象的内容(其中的任何属性/字段),它反映在调用位置。

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

【讨论】:

以上是关于参考和输出参数问题 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

带有带参数的函数的Bash脚本[重复]

如何在java中传递命令行参数[重复]

为啥 SVC 在输出中重复它的参数

获取将参数传递给jquery中当前函数的函数名称[重复]

参数和属性之间的区别[重复]

参数和参数之间的区别[重复]