1

我不明白关于将参数传递给 c# 中的方法的一件事。从我所看到的 c# 中的对象有时表现得就像是通过引用传递的,而一旦它们是通过值传递的。在这段代码中,我通过method()引用传递给一个,并通过值传递给一个。这两个都按预期执行。但是当我创建Update()并按值传递对象时,我看到它的行为就像它正在更新原始对象一样。

为什么我用 更新原始对象Update(myString input)但不更新它method(myString input)

这是不合逻辑的!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassPassing
{
class Program
{
    static void Main(string[] args)
    {
        myString zmienna = new myString();

        Update(zmienna);
        Console.WriteLine(zmienna.stringValue);
        Console.WriteLine(zmienna.stringValue2);
        Console.ReadLine();

        zmienna.stringValue = "This has run in main";
        zmienna.stringValue2 = "This is a help string";

        method(zmienna);
        Console.WriteLine(zmienna.stringValue);
        Console.WriteLine(zmienna.stringValue2);
        Console.ReadLine();

        method(ref zmienna);
        Console.WriteLine(zmienna.stringValue);
        Console.WriteLine(zmienna.stringValue2);

        Console.ReadLine();
    }

    static void method(myString input)
    {
        input = new myString();
    }

    static void method(ref myString input)
    {
        input = new myString();
    }

    static void Update(myString input)
    {
        input.stringValue2 = "This has run in update method";
    }
}

public class myString
{
    public string stringValue { get; set; }
    public string stringValue2 { get; set; }

    public myString() { stringValue = "This has been just constructed";   this.stringValue2 = "This has been just constructed"; }
}

}`

4

4 回答 4

4

您必须了解您的代码:

static void method(myString input)
{
    input = new myString();
}

在这里,您通过值传递对对象的引用

static void method(ref myString input)
{
    input = new myString();
}

在这里,您通过引用传递对对象的引用

static void Update(myString input)
{
    input.stringValue2 = "This has run in update method";
}

在这里,您再次按值传递对对象的引用

现在:

  1. 当您通过 value 传递对象引用时,您可以更改对象的内容,但不能更改引用本身(将其分配给另一个对象)。
  2. 当您通过引用传递对象引用时,您既可以更改对象的内容,也可以修改引用本身(将其分配给另一个对象)。

C#中真正的值传递仅发生在简单(int、float 等)类型和structs 的情况下:

class Program 
{
    public struct MyStruct
    {
        public int i;
    }

    public class MyClass 
    {
        public int i;
    }

    public static void Modify(MyStruct s) 
    {
        s.i = 99;
    }

    public static void Modify(MyClass c) 
    {
        c.i = 99;
    }

    public static void Main(string[] args) 
    {
        MyStruct myStruct = new MyStruct();
        myStruct.i = 20;
        MyClass myClass = new MyClass();
        myClass.i = 20;

        Modify(myStruct);
        Modify(myClass);

        Console.WriteLine("MyStruct.i = {0}", myStruct.i);
        Console.WriteLine("MyClass.i = {0}", myClass.i);

        Console.ReadKey();
    }
}

结果:

MyStruct.i = 20
MyClass.i = 99  

在这种情况下,的值保持不变,因为它是按值MyStruct传递给函数的。另一方面,' 的实例是通过引用传递的,这就是它的值发生变化的原因。MyClass

于 2013-11-14T14:33:47.783 回答
4

根本不传递对象。

对于引用类型(类、接口等)的表达式,默认情况下按值传递引用,但如果使用ref.

重要的是要理解 的值zmienna不是一个对象——它是一个引用。一旦你完成了排序,剩下的就变得简单了。它也不只是用于参数传递——它适用于所有东西。例如:

StringBuilder x = new StringBuilder();
StringBuilder y = x;
y.Append("Foo");
Console.WriteLine(x); // Prints Foo

这里 和 的值xy对同一个对象的引用——就像有两张纸,每张纸上都有相同的街道地址。因此,如果有人通过阅读写在上面的地址来访问房子x并将前门涂成红色,那么其他人通过阅读写在上面的地址访问同一所房子y,那么第二个人也会看到红色的前门。

有关更多详细信息,请参阅我关于引用和值类型以及参数传递的文章。

于 2013-11-14T14:34:09.160 回答
0

将计算机内存想象成一组盒子,您可以使用标签为它们命名。

myString zmienna = new myString();

在这里,您分配了一个带有实例的盒子myString,并有一个zmienna指向它的标签。然后:

static void method(myString input)
{
    input = new myString();
}

在这个方法中,input是另一个标签。调用您首先使标签input指向同一个框的方法,具有初始实例。但是,在方法的主体中,您分配了另一个框,并将标签 input更改为指向该新框。第一个盒子没有做任何事情,zmienna标签也没有做任何事情。

static void method(ref myString input)
{
    input = new myString();
}

在这里,由于ref关键字,您不仅传递了第一个“内存盒”的下落,而且还给出了实际的标签。所以这个方法的主体会更新你的标签zmienna以指向一个新创建的盒子,第二个实例是myString. 第一个盒子被遗忘了,因为没有标签指向它。

static void Update(myString input)
{
    input.stringValue2 = "This has run in update method";
}

在这种情况下,您传递第一个盒子的地址,方式与第一个方法完全相同。所以你有两个实验室:zmiennainput- 都指向同一个盒子。因此input.stringValue2访问由stringValue2指向的同一框中的字段zmienna

实际使用的精确术语是参考而不是我在此解释中使用的标签术语。我不知何故发现很多人发现这种方式更容易理解:)

于 2013-11-14T14:37:55.433 回答
0

这里可能有多个问题需要回答,但关于您的最后一个问题:

"Why do I update original object with Update(myString input) but do not update it with method(myString input)?"

在这里,您正在创建myString该类的一个新实例,而不是引用作为参数传递给该方法的原始实例。所以如果你改变了input.stringValue2方法内部的值,一旦你离开方法,你的值就会丢失。

static void method(myString input)
{
    input = new myString();
}

但是在这里,您引用的是传递给它的原始实例。当您离开此方法时,原始myString实例将保留stringValue2.

static void Update(myString input)
{
    input.stringValue2 = "This has run in update method";
}
于 2013-11-14T14:34:32.783 回答