【问题标题】:Passing reference type in C# [duplicate]在 C# 中传递引用类型 [重复]
【发布时间】:2013-09-13 13:27:08
【问题描述】:
class Test
{
    static void Func(StringBuilder myString)
    {
        myString.Append ("test");
        myString = null;
    }
    static void Main()
    {
        StringBuilder s1 = new StringBuilder();
        Func(s1);
        Console.WriteLine (s1);
    }
}

输出是“Test”,为什么不为空?

如果 s1 通过引用 传递给 Func(),那么为什么 myString.Append("test") 会更改它,而 myString = null 不会?

提前致谢。

【问题讨论】:

标签: c#


【解决方案1】:

您正在按值传递对对象的引用。

即对象的地址是按值传递的,但是对象和对象的地址是一样的。因此,当您调用方法时,VM 会复制引用;您只是在更改副本。

myString.Append 上,您使用复制的引用来获取对象(仍然只有一个对象),然后更改/调用该对象。

你认为你在做什么是这样的:

class Test
{
    static void Func(ref StringBuilder myString)
    {
        myString.Append("test");
        myString = null;
    }
    static void Main(string[] args)
    {
        StringBuilder s1 = new StringBuilder();
        Func(ref s1);
        Console.WriteLine(s1);
    }
}

更长的解释:http://javadude.com/articles/passbyvalue.htm

【讨论】:

    【解决方案2】:

    如果 s1 是通过引用 Func() 传递的,那么为什么 myString.Append("test") 确实改变了它

    它不是通过引用传递的,而是它的地址值传递给函数。

    假设S1 指向内存位置0x48,这将被传递给Func,其中Func 参数myString 将开始指向该位置。稍后,当您 Append 向该位置发送文本时,它会被添加。但是稍后当您将null 分配给myString 时,它开始指向任何内容,但原始位置保持不变。

    你应该看到:Parameter passing in C# by Jon Skeet

    考虑以下图表。 在第 1 步中,您创建一个 StringBuilder 类型的新对象,并让 S1 引用该对象。

    在第 2 步中,在将S1 传递给Func 之后,现在myString 也指向内存中的同一个对象。

    稍后当您Append,通过myString 发送文本时,它会更新原始对象,因为myString 指向对象持有的内存位置。

    在第 3 步中,当您将 null 分配给 myString 时,它会丢失 StringBuilder 对象的地址,但这不会更改对象或指针 S1 中的任何内容。

    【讨论】:

    • 你的解释有点混乱,但赞成链接。
    • @Dan,刚刚添加了一些图表来澄清
    • @Habib 你用什么工具来制作这种图表? +1顺便说一句..
    • @SonerGönül,Microsoft Visio
    • @Habib 非常感谢,明白了。
    【解决方案3】:

    在 C# 中,指向复杂类型的指针(引用)默认情况下是按值传递的。您必须指定它是通过引用传递的,如下所示:

    static void Func(ref StringBuilder myString)
    {
        myString.Append ("test");
        myString = null;
    }
    

    【讨论】:

    • 复杂类型是通过引用传递的,引用(指针)本身是通过值传递的。
    • @Dan - 答案已更新以澄清这一点。谢谢。 :-)
    【解决方案4】:

    ref 添加到函数中以通过引用传递它。

    static void Func(ref StringBuilder myString)
    {
        myString.Append ("test");
        myString = null;
    }
    

    然后这样称呼它:

    Func(ref s1);
    

    【讨论】:

      【解决方案5】:

      因为您将对 StringBuilder s1 的引用传递给 Func。 在 Func 内部,对同一 StringBuilder 实例的引用称为“myString”。 您首先告诉它做某事(“myString.Append("Test")),然后将引用 INSIDE Func 设置为 null。Append 的结果对 Main() 可见;设置为 null 的引用不会影响 Main 中的 s1。

      【讨论】:

        猜你喜欢
        • 2013-10-31
        • 1970-01-01
        • 2021-08-21
        • 2014-10-04
        • 1970-01-01
        • 2023-03-07
        • 2012-12-08
        • 1970-01-01
        • 2013-03-07
        相关资源
        最近更新 更多