【问题标题】:Pass reference by reference vs pass reference by value - C#按引用传递引用与按值传递引用 - C#
【发布时间】:2011-05-08 18:41:57
【问题描述】:

您好,

我知道按值传递和按引用传递之间的区别。但是通过 ref 传递引用(例如数组)并通过值传递数组是我似乎无法理解的。如何通过引用传递引用?

     int[] myArray = {1,2,3};
     PassByVal(myArray);
     PassByRef(ref myArray);

     PassByVal(int[] array)
     {    array = new int[] {7,8,9};   // will not work }

     PassByRef(ref int[] array)
     {    array = new int[] {10,11,12}; }  // will work

【问题讨论】:

  • 您是在什么背景下听到的?是否有任何示例与 ref by ref 相关联?
  • Interlocked.Exchange 就是一个很好的例子。它需要对它更改的对象变量的引用。 msdn.microsoft.com/en-us/library/bb337971.aspx
  • 如果您的问题已得到解答,请将其中一个答案标记为答案

标签: c# reference ref


【解决方案1】:

我建议您查看this link。它非常有用,包含关于Parameter passing in C# 的非常简单的示例。

引用参数不传递函数成员调用中使用的变量的值 - 它们使用变量本身。 不是在函数成员声明中为变量创建新的存储位置,而是使用相同的存储位置,所以函数成员中变量的值和引用参数的值会一直是相同。引用参数需要 ref 修饰符作为声明和调用的一部分 - 这意味着当您通过引用传递某些东西时它总是很清楚。再来看看我们之前的例子,只是把参数改成引用参数:

void Foo (ref StringBuilder x) {
    x = null;
}

...

StringBuilder y = new StringBuilder();
y.Append ("hello");
Foo (ref y);
Console.WriteLine (y==null); // will write TRUE

在你的例子中

int[] myArray = {1,2,3};
PassByVal(myArray);
PassByRef(ref myArray);

PassByVal(int[] array){
    // the function copy the value of the pointer in a new location of memory
    // the "copied" pointer still points to the array 123    

    // now you are modifying the object pointed by THE COPY of the pointer
    // the original pointer still points to array 123
    // the copy of the pointer will point to array 456
    array = new int[] {7,8,9}; 

} // will not work

PassByRef(ref int[] array){
   // here you are passing the pointer without creating a copy of it in a 
   // new location of memory

   // we have not a original pointer and a "copyed" pointer
   // we have only the original pointer and now whe point it to array 10,11,12
   array = new int[] {10,11,12}; 
}  // will work

【讨论】:

  • 谢谢这是一个非常有用的链接,我猜书籍并没有真正给出关于引用如何工作的非常详细的解释,他们只是提到对象通过引用传递......
  • 我写了一个新的回应。看看“在你的例子中”
【解决方案2】:

如果你通过引用传递一个引用,你可以使传入的变量指向一个新对象。如果按值传递引用,您仍然可以更改对象的状态,但不能使变量指向不同的对象。

示例:

void RefByRef(ref object x)
{
  x=new object(2);
}

void RefByValue(object x)
{
 x=new object(2);//Only changes a local variable and gets discarded once the function exits
}

void Test()
{
  object x1=1;
  object x1a=x1;
  RefByRef(ref x1);
  //x1 is now a boxed 2
  //x1a is still a boxed 1


  object x2=1;
  RefByValue(x2);
  //x2 is still a boxed 1
}

【讨论】:

    【解决方案3】:

    为了回答您的问题,我们先来看看 ValueTypes ValueType 保存值。也就是说,它并不指向另一个保存该值的内存位置,而是它的内存位置就是该值。

    所以 int i = 10;

    int j = i;

    这里发生的情况是将 i 的值的副本分配给 j。它们都具有相同的值,但它们在内存中的位置不同。换句话说,每次你将一个值类型分配给另一个值类型时,都会创建一个副本。

    与 ReferenceTypes 签约。

    对象 o = 10;

    对象 p = o;

    因为 o 是一个 ReferenceType o 指向一个保存值为 10 的内存位置(它确实是装箱的,但我会保持简单)。在下一行中,p 现在指向相同的内存位置。换句话说,引用类型有两件事要做。 1.地址指针 2. 保存实际“事物”的实际内存位置(该地址指向)。

    如果你做到了,那么我们可以继续通过值和引用传递。

    在 C# 中,参数是按值传递的。因此,如果您将 valueType 传递给需要 valuetype 参数的方法,那么

    int i = 10;
    SomeMethod(i);
    Console.WriteLine(i);
    
    static void SomeMethod(int value)
    {
      value = 20;
    }
    

    当调用 SomeMethod 时,i 的值的副本会发送到该方法。如果方法操作参数,它不会影响原始变量 i。所以你会在控制台窗口中看到的是 10;

    用引用类型收缩这个;

      class Program
      {
        static void Main(string[] args)
        {
          Customer c = new Customer() { Name = "Mike" };
          SomeMethod(c);
          Console.WriteLine(c.Name);
        }
    
        static void SomeMethod(Customer customer)
        {
          customer.Name = "John";
        }
      }
    
      class Customer
      {
        public string Name { get; set; }
      }
    

    因为 c 是一个引用类型。而 C# 按值传递参数。传递了引用的“值”的副本。即传递了 c 指向的地址的值。在该方法中,由于地址是相同的(它是一个副本,但它指向相同的内存位置),该方法能够操作对象的状态。因此,您将在控制台窗口中看到的是“John”而不是“Mike”。

    但是,如果方法尝试将另一个实例分配给参数(在本例中称为“客户”)。然后事情就变了。

      class Program
      {
        static void Main(string[] args)
        {
          Customer c = new Customer() { Name = "Mike" };
          SomeMethod(c);
          Console.WriteLine(c.Name);
        }
    
        static void SomeMethod(Customer customer)
        {
          customer = new Customer();
          customer.Name = "John";
        }
      }
    
      class Customer
      {
        public string Name { get; set; }
      }
    

    请注意,在该方法中,我们创建了一个 Customer 的新实例并将其分配给参数 customer,我们将这个新实例的名称设置为“John”。我们将在控制台窗口中看到的是“Mike”而不是 john。

    这是因为在将原始变量 (c) 传递给方法之前已对其进行了复制。虽然现在在方法中,我们有另一个地址,然后操作该新地址,因此原始实例不受影响。有意义吗?

    好的,如果这有意义的话。那么如果我们真的希望 SomeMethod 能够做我们试图做的事情呢?那么,参数不能通过值传递,但必须通过引用传递。这意味着正在传递变量 c 和两部分(它指向的地址的值和地址本身)。所以现在你通过引用传递一个引用类型。

      class Program
      {
        static void Main(string[] args)
        {
          Customer c = new Customer() { Name = "Mike" };
          SomeMethod(ref c);
          Console.WriteLine(c.Name);
        }
    
        static void SomeMethod(ref Customer customer)
        {
          customer = new Customer();
          customer.Name = "John";
        }
      }
    
      class Customer
      {
        public string Name { get; set; }
      }
    

    【讨论】:

      【解决方案4】:

      这可能看起来有点令人困惑,但实际上并没有那么棘手。当您将引用类型的实例分配给变量时,您可以说该变量的 将是对象的 引用,而不是对象本身。当您将该变量按值传递给另一个方法时,您传递的是引用的副本。被调用的方法将“看到”与调用代码相同的实例。如果您改为通过引用传递变量,则调用方法会看到与调用代码一样引用的相同副本

      它们之间的行为区别在于,当您通过引用传递变量时,被调用的方法可能会将 another 引用分配给该变量(使其引用另一个相同类型的实例),并且调用代码将看到此更改。除非您进行此类分配,否则无需使用ref

      【讨论】:

        猜你喜欢
        • 2023-03-02
        • 2013-04-12
        • 1970-01-01
        • 2012-07-03
        • 1970-01-01
        • 2016-10-22
        • 2017-01-19
        相关资源
        最近更新 更多