通过价值和;通过参考传递

时间:2010-05-26 06:34:13

标签: c# .net string pass-by-reference

请您解释一下C#Class的以下行为。我希望classResult为“Class Lijo”;但实际值是“已更改”。

我们正在制作参考文献的副本。虽然副本指向同一地址,但接收参数的方法不能更改原始地址。

仍然为什么价值会发生变化?

public partial class _Default : Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        String nameString = "string Lijo";

        Person p = new Person();
        p.Name = "Class Lijo";

        Utilityclass.TestMethod(nameString, p);
        string classResult = p.Name;
        Response.Write(nameString + "....." + classResult);
    }
}

public class Utilityclass
{
    public static void TestMethod(String nameString, Person k)
    {
        nameString = "Changed";
        k.Name = "Changed";
    }
}

public class Person
{
    public string Name
    {
        get; set;
    }
}

更新:当我传递一个字符串时,它实际上没有被更改。

6 个答案:

答案 0 :(得分:22)

最简短的回答是:阅读my article on parameter passing,其中详细介绍了这一点。

稍微长一点的答案是比较这两种方法,两种方法都使用 value 参数:

public void ChangeMe(string x)
{
    x = "changed";
}

public void ChangeMe(Person x)
{
    x.Name = "changed";
}

在第一种情况下,您要更改参数值。这与原始论点完全隔离。您无法更改字符串本身的内容,因为字符串是不可变的。

在第二种情况下,您正在更改参数值引用的对象的内容。这并没有改变参数本身的价值 - 它将是相同的参考。举一个现实世界的例子,如果有人向你的房子提供改变房子内容的东西,但它不会改变你家的地址。

如果您将第二种方法更改为:

public void ChangeMe(Person x)
{
    x = new Person("Fred");
}

然后调用者不会看到任何变化。这更接近于您对字符串所做的事情 - 您正在使参数引用不同的对象,而不是更改现有对象的内容。

现在,当您使用ref参数时,调用者用作参数的变量与参数“别名” - 因此,如果更改参数的值,则会更改参数的值同样。所以如果我们改变最后一个方法:

public void ChangeMe(ref Person x)
{
    x = new Person("Fred");
}

然后:

Person y = new Person("Eric");
ChangeMe(ref y);
Console.WriteLine(y.Name);

这将打印出“Fred”。

要理解的关键概念是变量的值永远不是对象 - 它可以是值类型值或引用。如果更改了对象的数据,则通过其他引用可以看到该更改。一旦你理解复制一个引用与复制一个对象是不一样的,那么其余部分就会很容易理解。

答案 1 :(得分:7)

Person是一种引用类型,因此无论您使用refout还是什么都没有,您始终可以在方法内修改它。您永远不会将真人对象传递给方法,您将指针作为参考传递,而不是实际的Personref关键字对值类型(例如,structs,int,float,DateTime,...)非常有用。 它也可以与引用类型一起使用,但仅用于指示行为但不能强制执行它。如果将它与引用类型一起使用,它允许您更改此引用所指向的对象。

答案 2 :(得分:0)

当您将P传递给测试方法时,您将其位置传递到内存中,而不是对象的副本。在方法体中拾取引用并修改原始值。

答案 3 :(得分:0)

Utilityclass.TestMethod无法将局部变量p更改为指向不同的Person对象,因为您没有通过引用传递,但它仍可以自由调用任何方法或更改任何属性在它传递的对象上。因此Name属性可以在Utilityclass.TestMethod内修改。

答案 4 :(得分:0)

这个问题已被大部分回答,但我想您可能想试试这个片段(如果您尝试使用整数,可以获得奖励积分!)

class Program
{
    static void Main(string[] args)
    {            
        Person p = new Person();
        p.Name = "Class Lijo";

        Utilityclass.TestMethod(p);
        string classResult = p.Name;
        Console.WriteLine(classResult);
        Utilityclass.TestMethod2(ref p);
        classResult = p.Name;  // will bomb here           
        Console.WriteLine(classResult);
    }
}

public class Utilityclass
{
    public static void TestMethod(Person k)
    {
        k.Name = "Changed";
        k = null;
    }

    public static void TestMethod2(ref Person k)
    {
        k.Name = "Changed Again!";
        k = null;
    }
}

答案 5 :(得分:-1)

当您将引用类型参数传递给方法时,这意味着该方法可以直接访问该参数而不是它的副本....

结果是改变了。