我对这段代码感到有点困惑.
public static void Foo(A p)
{
p.SomeProp = "ccc";
p = null; // !!!
}
static void Main(string[] args)
{
A p = new A();
Foo(p);
Console.WriteLine("SomeProp is: " + p.SomeProp);
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
输出是:
"SomeProp是:ccc "
但我本来期望一个NullReferenceException.
但是,如果我这样更改它,使用ref修饰符:
public static void Foo(ref A p)
{
p.SomeProp = "ccc";
p = null;
}
static void Main(string[] args)
{
A p = new A();
Foo(ref p);
Console.WriteLine("SomeProp is: " + p.SomeProp);
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
我得到一个NullReferenceException - 第二个对我来说是可以理解的.
但是怎么可能,在第一段代码中p没有设置为null,但属性是否设置了它的值?
我的问题是:如果它不是对原始实例的引用,那么第一段代码中Foo方法的p参数是什么?
顺便说一句.这是A类的定义
public class A
{
public string SomeProp;
}
Run Code Online (Sandbox Code Playgroud)
Joe*_*orn 17
在.Net中,除非您明确使用或关键字,否则所有内容都按值传递.对于引用类型,这意味着传递引用的副本. refout
在您的第一个示例中,这意味着您的p变量仍然是对同一对象的引用,因此设置属性的工作方式与您期望的一样.但是当你将引用本身设置为null时,所有你改变的都是副本.
p.SomeValue = "ccc";
Run Code Online (Sandbox Code Playgroud)
说:
将该对象上的属性SomeValue的值设置为"ccc"
p = null;
说:
它并不是说将p引用的对象更改为null,而是将局部变量p引用为null.
默认情况下,当您传递类型A的参数时,例如在方法调用"Foo(p)"中,您没有传递由p引用的对象,甚至是引用p,而是对p引用的对象的引用.它们引用相同的对象,但它们不是相同的引用.即,"public static void Foo(A p)"中的引用p与"Foo(p)"中的p不同,但它们引用相同的对象.
您可以使用ref参数来改变此行为.这会改变它以使它们是相同的引用,并且改变一个的值会改变另一个的值.