Ref 和 Out 参数问题

Ref and Out Parameters Questions

我以为我理解其中的区别,但现在我不太确定了。我已经多次阅读技术答案,但我不明白发生了什么。我有这个例子。

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) 中将其视为变量 "value"。到目前为止,我是否对任何事情都挂断了电话?如果我用过

int value = 0;
Example1(value);
Console.WriteLine(value); // this would then return 1 correct?

那么,out 关键字发生了什么?与 ref?

相同

在第一个示例中,您没有指定变量是引用,因为它是基本类型,所以它只是复制提供的数字。所以 Example1 中的 valueMainvalue 的副本。

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

在第三个示例中,out 关键字的作用与第二个相同,不同之处在于它在进入函数时被初始化为 0。因此,它只是一个用于返回某种数据的参数。该值只是在退出函数时传递。

看看这是否有帮助:

没有"decorators"

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" 关键字。如果将引用类型传递给方法(即 class)并更改其内部结构,这些将影响调用者。

默认参数:

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>
}

总结:输出参数类似于 return 变量,但通过方法的签名传入。最常见的示例是 TryParse,其中方法 return 的重要信息和取决于该信息的 out 参数是否有效(如果为真则有效)。

好的,它与评论中的链接问题重复,但我会尽力为您解释。

未修饰的参数

案例 A:public void MyFunc(int x) { }

-或-

案例 B:public void MyFunc(MyClass y) { }

在案例 A 中,参数是值类型,默认情况下,值类型作为原始值的副本传递给函数。这并不意味着您不能修改该值,但该值不会反映回调用位置。这对所有值类型都是一样的,值在传递给函数之前被复制

在案例B中,参数是一个引用类型。这些类型默认按原样传递。它们不会被复制,但您不能更改引用(通过为类型分配 newnull 值)。您可以更改对象的内容(其中任何 property/field),它 反映回调用位置。

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) { }

在这里,您基本上是在为函数定义其他 return 类型。它的方法参数告诉调用者期望结果代替 x 变量。这对两者都是一样的。在任何情况下,调用者都不应该期望 x 之前的任何值在之后都是相同的。事实上你可以预料它不会是一样的,因为在允许return之前该方法需要给x赋一个新值。

out 基本上意味着您为 return 值提供了一个位置,对于值类型,只需使用默认构造函数,对于引用类型,在传递之前将值初始化为 null英寸