-3

我知道发送给函数的值默认作为值传递,并且该方法接收变量的副本。我知道当一个变量通过引用传递时,该方法可以从它被调用时改变变量的值。话虽如此,有人可以帮助解释这些简单插图中发生了什么吗?提前致谢。我猜是通过引用传递表达式吗?

using System;
class Program
{
    static void Main(string[] args)
    {
        int x = 2;
        int y = 20;
        Console.WriteLine(Add(x, y));
    }

    static int Add(int x, int y)
    {
        int ans = x + y;
         x = 20;
         y = 40;
       // return x+y;
         return ans;
        //returns 22
    }
}

进而

using System;
class Program
{
    static void Main(string[] args)
    {
        int x = 2;
        int y = 20;
        Console.WriteLine(Add(x, y));
    }

    static int Add(int x, int y)
    {
        int ans = x + y;
         x = 20;
         y = 40;
       return x+y;
      //   return ans;
        //returns 60
    }
}
4

9 回答 9

2

没有什么奇怪的事情发生,也没有什么与参数传递方式有关。

在第一个示例中:

// parameters in: x = 2, y = 20.
int ans = x + y;
// now ans contains the value 22.
x = 20;
y = 40;
// now x and y has changed, but the value in ans
// is already calculated and doesn't change.
return ans;
// returns 22;

在第二个例子中:

// parameters in: x = 2, y = 20.
int ans = x + y;
// now ans contains the value 22.
x = 20;
y = 40;
// now x and y has changed, but not ans.
return x+y;
// the value of the expression is calculated with the current
// values, and 60 is returned.
// the variable ans still contains 22, but that isn't used here.
于 2012-09-27T18:12:55.303 回答
1

在第一种情况下Add返回 x + y。在第二种情况下Add返回 20 + 40;

当你在函数中赋值时,你改变了变量的本地副本。不是实际值。

例如:

using System;
class Program
{
    static void Main(string[] args)
    {
        int x = 2;
        int y = 20;
        Console.WriteLine(Add(x, y));
        // x is still 2, y is still 20
    }

    static int Add(int x, int y)
    {
        int ans = x + y;
        // You calculate the parameters and store it in the local variable
        x = 20;
        y = 40;
        // You've adapted your local COPIES of the variables
        return ans;
        // You return the answer which was calculated earlier
    }
}

但是,这是因为您正在处理值类型 ( struct)。如果您正在处理引用类型(class),那么这是另一回事,例如:

using System;
class Program
{
    private class Numbers
    {
        public int X;
        public int Y;
    }

    static void Main(string[] args)
    {
        Numbers num = new Numbers();
        num.x = 2;
        num.y = 20;
        Console.WriteLine(Add(num)); // Prints 2 + 20 = 22
        // num.x is now 20, and num.y is now 40
        Console.WriteLine(Add(num)); // Prints 20 + 40 = 60
    }

    static int Add(Numbers num)
    {
        int ans = num.x + num.y;
        // You calculate the result from the public variables of the class
        num.x = 20;
        num.y = 40;
        // You change the values of the class
        return ans;
        // You return the answer which was calculated earlier
    }
}

在 C# 中有 4 种“类型”的传递参数:

  • 按值传递值类型 ( struct)。
  • 按值传递引用类型 ( class)。
  • 通过引用传递值类型。
  • 通过引用传递引用类型。

演示这 4 个的简短示例:

static void Main()
{
    int x = 5; // Value type
    List<int> list = new List<int>(new [] { 1, 2, 3 }); // Reference type

    ValueByValue(x); // x is still 5
    ReferenceByValue(list) // list still contains { 1, 2, 3 }
    ValueByReference(ref x); // x is now 10
    ReferenceByReference(ref list); // list is now a new list containing only { 4, 5, 6 }
}

static void ValueByValue(int x)
{
    x = 10; // Changes local COPY of x
}

static void ReferenceByValue(List<int> list)
{
    list = new List<int>(new [] { 4, 5, 6 }); // Changes local COPY of list
}

static void ValueByReference(ref int x)
{
    x = 10; // Changes the actual x variable in the Main method
}

static void ReferenceByReference(ref List<int> list)
{
    list = new List<int>(new [] { 4, 5, 6 }); // Changes the actual list in the Main method
}
于 2012-09-27T18:09:40.760 回答
1

在这两种情况下,它都是按值传递的。

但是在第二种情况下,如果您尝试在调用函数中打印 x 和 y 的值,它将仅返回 x=2 和 y=20。

x=20 和 y=40 只是在 add 函数中针对第二种情况进行了更改,它们不会将修改后的内容返回给调用者。

于 2012-09-27T18:09:45.307 回答
1

这两个都说明了按值传递,通常是值类型语义。

在您的第一个示例中,您是在说:

int ans = x + y;

这会在那个时候评估xandy并将它们加在一起以存储在 ans 中,稍后设置x和新值不会影响 的值。 yans

这样考虑:

static int Add(int x, int y)
{
    int ans = x + y;  // evaluates ans = x + y = 2 + 20 = 22
     x = 20;          // here ans = 22, x = 20, y = 20
     y = 40;          // here ans = 22, x = 20, y = 40
     return ans;      // returns ans which is still 22 since x & y are independent
}

在您的第二个示例中,您将添加延迟到设置新值之后,因此 和 的新值x用于y计算

return x + y;

所以,本质上,你得到:

static int Add(int x, int y)
{
    int ans = x + y;  // ans = 22, x = 2, y = 20
     x = 20;          // ans = 22, x = 20, y = 20
     y = 40;          // ans = 22, x = 20, y = 40
   return x+y;        // evaluates x + y = 60
}

认为可能让您感到困惑的是:

ans = x + y;

不是一个函数,它是一个被评估和返回的表达式,更改xy此语句执行后不会再次影响ans

再次要记住的关键点是在执行该语句时进行ans = x + y;评估。进一步的变化和不在这里发挥作用。xyxy

于 2012-09-27T18:10:18.607 回答
1

两者之间唯一真正的区别是,您在第一个中的 return 语句是返回保存在内存位置的值,该内存位置由该内存位置标识,该内存位置ans包含 22 的值。

在第二个中,return 语句返回由 标识的内存位置x的当前值加上由标识的内存位置的当前值y,它们是该方法的本地值(按值传递)并由您更改为 20和 40,分别。这个值当然是 60。

需要注意的重要一点是,按值传递意味着为值分配了本地堆栈内存(或其他)xy并且不x and从调用者的方法中引用值 y`。

于 2012-09-27T18:11:40.150 回答
1

表达式总是产生一个RVALUE ..

一个例子会有所帮助

int x=50,y=20;

->右值

不能将任何内容分配给右值。

Example 
x+y=500;//INVALID

->左值

你可以给它赋值。

Example
x=500;//VALID
y=545*33+4;//VALID

所以,表达式永远不能通过引用传递

于 2012-09-27T18:14:09.707 回答
0

这里参数是按值传递的。只是在第二个示例中,因为 x 和 y 分别修改为 20 和 40,所以 60 作为两者的总和返回。

于 2012-09-27T18:10:03.630 回答
0
 static int Add(int x, int y) 
 { 
      int ans = x + y; 
      x = 20; 
      y = 40; 
      // return x+y; 
      return ans; 
      //returns 22 
 }

在这种方法中,计算是在修改之前进行的,因此是在变量改变之前存储的。

 static int Add(int x, int y) 
 { 
      int ans = x + y; 
      x = 20; 
      y = 40; 
      return x+y; 
      // return ans; 
      //returns 60 
 }

在此方法中,ans不使用变量,更改 x 和 y 值,然后返回 的数学结果x + y,而不是ans

此外,这些方法都不是按引用传递,它们都是按值传递,按引用传递方法在参数前面有ref关键字。

 static int Add(ref int x, int y) // x is the referenced variable in this example
于 2012-09-27T18:10:17.623 回答
0

不,此表达式不是按引用调用的,它唯一的按值调用。通过引用调用更改参数的值意味着您正在传递变量的引用。

例子 :

using System;
class Program
{
    static void Main(string[] args)
    {
        int x = 2;
        int y = 20;


        Console.WriteLine("SUM  :: " + AddByValue(x, y));  // Call by value
        Console.WriteLine("X :: " + x + ", Y :: " + y);  // Nothing change to variable

        Console.WriteLine("SUM  :: " + AddByRef(ref x, ref y));  // Call by reference
        Console.WriteLine("X :: " + x + ", Y :: " + y);  // Value changed

    }

    static int AddByValue(int x, int y)
    {
        int ans = x + y;
         x = 20;
         y = 40;
       return ans;
    }

    static int AddByRef(ref int x, ref int y)
    {
        int ans = x + y;
        x = 20;
        y = 40;
       return ans;
    }


}

输出 :

SUM  :: 60
X :: 2, Y :: 20

SUM  :: 60
X :: 20, Y :: 40
于 2012-09-27T18:12:48.237 回答