在C#中按值传递对象引用。

huangapple go评论63阅读模式
英文:

passing object references by value in C#

问题

var test = new TestClass();

SomeMethod(test);
Console.WriteLine(test);

SomeMethod2(test);
Console.WriteLine(test);

Console.ReadKey();

void SomeMethod(TestClass a)
{
    a = null; 
}

void SomeMethod2(TestClass a)
{
    a.intThing = 1;
}

public class TestClass
{
    public int intThing = 0;

    public override string ToString()
    {
        return $"{intThing}";
    }
}

这段代码存在一些混淆的情况 - SomeMethod 方法接收参数 a 并将 a 设置为 null,并不会修改初始的 test 对象,但在 SomeMethod2 方法中将 intThing 字段设置为 1 会修改初始的 test 对象。这是为什么?为什么我不能在 SomeMethod 中将 test 对象设置为 null 呢?我知道 test 对象的引用以传值的方式传递给方法 - 我只是不明白为什么将 a 设置为 null 不会影响对象。

如果您想要了解这种行为背后的原因,这是因为 C# 中的参数传递方式是按值传递。在 SomeMethod 方法中,参数 a 接收了 test 对象的副本,而在 SomeMethod2 方法中,也是接收了 test 对象的副本。当您在 SomeMethod2 中修改副本的字段时,它会影响到原始的 test 对象,因为它们引用的是同一个对象。但在 SomeMethod 中,虽然将 a 设置为 null,但这只是将参数 a 的引用更改为 null,并不会影响原始的 test 对象。

要实现在方法内部将 test 对象设置为 null,您可以将参数 a 改为 ref 修饰符,这样就可以传递参数的引用而不是副本,像这样:

void SomeMethod(ref TestClass a)
{
    a = null; 
}

然后调用时:

SomeMethod(ref test);

这样就可以在 SomeMethod 中将 test 对象设置为 null。

英文:
var test = new TestClass();

SomeMethod(test);
Console.WriteLine(test);

SomeMethod2(test);
Console.WriteLine(test);

Console.ReadKey();

void SomeMethod(TestClass a)
{
    a = null; 
    
}

void SomeMethod2(TestClass a)
{
    a.intThing = 1;

}

public class TestClass
{
    public int intThing =0;

    public override string ToString()
    {
        return $"{intThing}";
    }
}

A bit confused on the output of this here - SomeMethod which passes in a and sets a=null does not modify the initial test object whatsoever, however setting the intThing field to 1 in SomeMethod2 modifies the initial test object. Whats going on with this? Why can't I set the test object to null in SomeMethod by passing it in? I know that the reference to test in memory is being passed by value into the methods - I'm just confused why setting a equal to null doesn't act on the object.

答案1

得分: 4

因为你是通过值传递引用对象,a 只是一个本地变量,存储了内存中对象的引用,并且将 a 设置为 null 不会影响存储该引用的其他变量。另一方面,第二个方法中的 a.intThing = 1; 修改了引用对象(即 testa 都指向内存中的同一位置,并对其进行了更改)。

你可以使用 ref 关键字 使第一个片段按预期工作:

在方法的参数列表中使用 ref 关键字表示参数是按引用传递的,而不是按值传递的。ref 关键字使形式参数成为参数的别名,参数必须是一个变量。换句话说,对参数的任何操作都会影响参数本身。

SomeMethod(ref test);

void SomeMethod(ref TestClass a)
{
    a = null;     
}

这将导致 test 被设置为 null

还可以阅读:

英文:

Because you are passing reference to the object by value, a is just a local variable storing the reference to the object in memory and setting a to null will not affect other variables storing that reference. a.intThing = 1; in the second method on the other hand modifies the object by reference (i.e. both test and a point to the same place in memory and you change it).

You can use ref keyword to make the first snippet work as desired:

> When used in a method's parameter list, the ref keyword indicates that an argument is passed by reference, not by value. The ref keyword makes the formal parameter an alias for the argument, which must be a variable. In other words, any operation on the parameter is made on the argument.

SomeMethod(ref test);

void SomeMethod(ref TestClass a)
{
    a = null;     
}

This will result in test set to null.

Read also:

答案2

得分: 2

你已将引用设置为null。这对引用指向的内容没有任何影响。

如果你想通过引用传递引用,你可以使用ref关键字:

var test = new TestClass();

SomeMethod(ref test);
Console.WriteLine(test);

SomeMethod2(ref test);
Console.WriteLine(test);

Console.ReadKey();

void SomeMethod(ref TestClass a)
{
    a = null; 
}

void SomeMethod2(ref TestClass a)
{
    a.intThing = 1;
}
英文:

You've set the reference to null. That doesn't have any effect on what the reference is pointing at.

If you want to pass the reference by reference, you can use the ref keyword:

var test = new TestClass();

SomeMethod(ref test);
Console.WriteLine(test);

SomeMethod2(ref test);
Console.WriteLine(test);

Console.ReadKey();

void SomeMethod(ref TestClass a)
{
    a = null; 
    
}

void SomeMethod2(ref TestClass a)
{
    a.intThing = 1;

}

答案3

得分: 1

参数本身通常总是按值传递。void SomeMethod(TestClass a) 在堆栈上复制一个引用,并将复制的引用设置为null

但如果访问成员,您将修改引用的对象。

使用ref关键字传递对象可以解决此问题,并允许您主动修改传入的引用本身。

英文:

Parameters themselves are usually always passed by-value. void SomeMethod(TestClass a) copies a reference onto the stack and you set the copied reference to null.

But if you access a member, you modify the referenced object instead.

Passing an object using the ref keyword solves this and lets you actively modify the passed in reference itself.

huangapple
  • 本文由 发表于 2023年7月20日 13:39:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76726952.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定