我不了解将参数传递给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"; }
}
}`
答案 0 :(得分:4)
您必须了解您的代码:
static void method(myString input)
{
input = new myString();
}
这里按值 传递对象的引用
在此您通过引用 这里再次传递对象的引用 现在: 在C#中传递值的真实仅在简单(int,float等)类型的情况下发生,并且在 结果: 在这种情况下,static void method(ref myString input)
{
input = new myString();
}
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
传递给函数。另一方面,struct
s的情况下: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
的实例通过引用传递 ,这就是它的值发生变化的原因。
答案 1 :(得分:4)
对象。
对于引用类型(类,接口等)的表达式,默认情况下按值传递引用,但如果使用ref
,则通过引用传递变量。
重要的是要理解zmienna
的值不是对象 - 它是一个参考。一旦你对它进行了排序,剩下的就变得简单了。它不仅适用于参数传递 - 它适用于所有内容。例如:
StringBuilder x = new StringBuilder();
StringBuilder y = x;
y.Append("Foo");
Console.WriteLine(x); // Prints Foo
这里x
和y
的值是对同一个对象的引用 - 就像有两张纸,每张纸都有相同的街道地址。因此,如果有人通过阅读x
上写的地址并将前门涂成红色来访问房屋,那么其他人通过阅读y
上写的地址访问同一所房子,第二个人会看到一个红色前门也是。
有关详细信息,请参阅reference and value types和parameter passing上的文章。
答案 2 :(得分: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";
}
答案 3 :(得分: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";
}
在这种情况下,您传递第一个框的地址,方式与第一个方法完全相同。所以你有两个实验室:zmienna
和input
- 都指向同一个盒子。因此,input.stringValue2
会在stringValue2
指向的同一个框中访问字段zmienna
。
实际使用的精确术语是 reference ,而不是我在此解释中使用的 label 术语。我发现许多人发现这种方式更容易理解:)