c# - 为什么传入带有 ref 关键字的方法的实例在创建新对象后可以保持不变?

标签 c# object methods reference instance

我遇到了这个棘手的问题。请参阅以下代码:

public class Foo
    public int A { get; set; }
}

static void Main(string[] args)
{
    Foo foo1 = new Foo();
    Foo foo2 = new Foo();

    ChangeObject1(foo1);
    ChangeObject2(ref foo2);

    Console.WriteLine("Foo1 = " + foo1.A);
    Console.WriteLine("Foo2 = " + foo2.A);
    Console.ReadKey();
}

static void ChangeObject1(Foo foo)
{
    foo.A += 1;
    foo = new Foo();
}

static void ChangeObject2(ref Foo foo)
{
    foo.A += 1;
    foo = new Foo();
}

经过一些测试,foo1.A等于1,而foo2.A仍然等于0。据我了解,这是因为第二个方法通过引用而不是值传入实例。这会更改实例的内容,因此当在方法中创建并分配新对象时,不再定义该值。

但是想到这一点让我很困惑,因为我觉得第一个方法应该有类似的效果,即使它是按值传递的,因为实例的内容仍然在方法之外更改。

有人知道到底发生了什么吗?谢谢!

最佳答案

我假设您使用的是 c# 或 java。无论哪种方式,概念都是一样的

当你声明 foo 变量时

Foo foo1 = new Foo()

您正在声明所谓的引用类型。 (所有代表类的对象都是引用类型)

所以,存储在 foo1 中的值并不是真正的 Foo,但它是一个保存该 Foo 内存地址的值.

当你打电话

    static void ChangeObject1(Foo foo)
    {
        foo.A += 1;
        foo = new Foo();
    }

您正在传递该引用的副本。因此,当您执行 foo.A += 1 时,您正在更改刚刚传入的对象的成员值。

当您执行 foo = new Foo(); 时,您只是更改了引用的副本,而不是原始对象引用本身。

现在,当你打电话时

    static void ChangeObject2(ref Foo foo)
    {
        foo.A += 1;
        foo = new Foo();
    }

您传递的不是 Foo 地址的副本,而是传递 Foo 地址的地址。

您可以将其视为传递原始 Foo 地址本身。

因此,当您调用 foo = new Foo() 时,之前对 foo 做了什么并不重要。您刚刚用全新的 Foo 对象的地址覆盖了您的地址。

如果您将方法更改为如下所示

    static void ChangeObject2(ref Foo foo)
    {
        foo.A += 1;
    }

那么你应该注意到变化

Here's a page that explains reference types它是用 java 编写的,但同样的原理也适用于 c#

关于c# - 为什么传入带有 ref 关键字的方法的实例在创建新对象后可以保持不变?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12375678/

相关文章:

c# - 返回的json中的双引号

C++类实例化和内部调用方法

Java : Instantiating method variables

c# - DateTime.Parse 和 Convert.ToDateTime 之间有什么区别?

c# - Azure 诊断 - 加密 cscfg 中的连接字符串

java - 为什么在打印对象时调用 toString() 方法?

javascript - 为什么全局对象属性在函数后不更新?

actionscript-3 - 冲突范围 : Global Functions and Class Methods of the Same Name

c# - 我如何解决 NHibernate.MappingException

javascript - angularjs 过滤器 |不过滤所有对象属性