按引用传递引用与按值传递引用 - C#

发布于 2024-10-02 04:44:37 字数 372 浏览 7 评论 0原文

您好,

我明白按值传递和按引用传递之间的区别。但是通过 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

Greetings,

I get the difference between pass by value and pass by reference. But pass reference (such as array) by ref and pass array by value is something i can't seem to comprehend. How can you pass a reference by reference?

     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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

王权女流氓 2024-10-09 04:44:37

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

示例:

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
}

If you pass a reference by reference you can make the variable passed in point to a new object. If you pass the reference by value you still can change the state of the object, but you can't make the variable point to a different object.

Example:

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
}
小草泠泠 2024-10-09 04:44:37

我建议您查看此链接。它非常有用,包含关于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

I suggest that you check out this link. It's quite useful and contains very simple examples about Parameter passing in C#.

Reference parameters don't pass the values of the variables used in the function member invocation - they use the variables themselves. Rather than creating a new storage location for the variable in the function member declaration, the same storage location is used, so the value of the variable in the function member and the value of the reference parameter will always be the same. Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference. Let's look at our previous examples, just changing the parameter to be a reference parameter:

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

...

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

IN YOUR EXAMPLE

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
独留℉清风醉 2024-10-09 04:44:37

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

所以
整数 i = 10;

整数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; }
  }

In order to answer your question let's first look at ValueTypes
A ValueType holds the Value. That is it does not in turn point to another memory location that holds the value but rather it's memory location is the value.

so
int i = 10;

int j = i;

What happens here is that a copy of the value of i is assigned to j. They both have the same value but they are different locations in memory. In oter words, each time you assign a valuetype to another valuetype, a copy is made.

Contract this with ReferenceTypes.

object o = 10;

object p = o;

because o is a ReferenceType o points to a memory location that holds the value of 10 (it is really boxed but I'll keep it simple). In the next line p now points to the same memory location. In other words, reference tyes have two things going.
1. An address pointer
2. The actual memory location (that address points to) that holds the actual "thing".

If you get it do far, then we can move on the passing by value and by reference.

In C# parameters are passed by value. So if you're passing a valueType to a method that expects a valuetype parameter, then

int i = 10;
SomeMethod(i);
Console.WriteLine(i);

static void SomeMethod(int value)
{
  value = 20;
}

When the call is made to SomeMethod a copy of the value of i is sent to the method. If the method manipulates the parameter, it does not affect the original variable i. So what you'll see in the console window is 10;

contract this with reference types;

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

Since c is a reference type. And C# passes parameters by value. a copy of the "value" of the reference is passed. That is the value of the Address c is pointing to is passed. In the method, since the address is the same (it's a copy but it points to the same memory location), the method is able to manipulate the state of object. So what you'll see in the console window is "John" and not "Mike".

However, if the method attempts to assign another instance to the parameter (called "customer" in this case). then things change.

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

Notice that in the method we create a new instance of a Customer and assign it to the parameter customer and we set the name of this new instance to "John". What we'll see in the console window is "Mike" and not john.

That is because a copy of the original variable (c) was made before passing it to the method. While now in the method we have another address and then manipulate that new address so the original instance is untouched. Make sense?

Ok, if that makes sense. then what if we actually wanted the SomeMethod to be able to do what we attempted to do? Well, then the parameter can't be passed by value but it has to be passed by reference. Meaning that the variable c and the two part (the value of address it is pointing and the address itself) are being passed. So now you're passing a reference type by reference.

  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; }
  }
毁梦 2024-10-09 04:44:37

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

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

This may seem a bit confusing, but it's really not that tricky. When you assign an instance of a reference type to a variable, you could say the value of that variable will be a reference to the object, not the object itself. When you pass that variable by value to another method, you are passing a copy of the reference. The called method will "see" the same instance as the calling code does. If you instead pass the variable by reference, the calling method gets to see the same copy of the reference as the calling code does.

The difference in behavior between these to is that when you pass the variable by reference, the called method might assign another reference to the variable (make it reference another instance of the same type), and the calling code will see this change. Unless you make such assignments, there is no need to use ref.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文