Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 引用类型与值类型_C#_.net_Oop_Reference - Fatal编程技术网

C# 引用类型与值类型

C# 引用类型与值类型,c#,.net,oop,reference,C#,.net,Oop,Reference,我正在阅读C#中的结构和类,据我所知,结构是值类型,类是引用类型。但我对类对象作为参数传递给方法时的行为有点困惑 假设我有以下代码: public class Program { public static void Main(string[] args) { var program = new Program(); var person = new Person { Firstname = "Bob",

我正在阅读C#中的结构和类,据我所知,结构是值类型,类是引用类型。但我对类对象作为参数传递给方法时的行为有点困惑

假设我有以下代码:

public class Program
{
    public static void Main(string[] args)
    {
        var program = new Program();
        var person = new Person
        {
            Firstname = "Bob",
        };

        Console.WriteLine(person.Firstname);
        program.ChangeName(person);
        Console.WriteLine(person.Firstname);
        program.Kill(person);
        Console.WriteLine(person.Firstname);
        Console.Read();
    }

    public void ChangeName(Person p)
    {
        p.Firstname = "Alice";
    }

    public void Kill(Person p)
    {
        p = null;
    }
}

当我将
Person
类的实例传递给
Program.ChangeName()
并将
Person.Firstname
的值更改为
Alice
时,更改会反映在我的
Program.Main()
中实例化的原始Person对象上,这正是我所期望的,
p
参数是对
person
的引用。但是,当我尝试将
p
设置为
null
时,似乎没有任何更改。这是为什么?

您正在将引用的副本设置为null,这不会影响原始值

它类似于(在C++中)

引用实际上是按值传递的,您不能更改它。您可以更改其指向的对象的属性,但是:

ptr->Name = "Bob";

显然会影响原始对象。

您正在将引用副本设置为null,这不会影响原始值

它类似于(在C++中)

引用实际上是按值传递的,您不能更改它。您可以更改其指向的对象的属性,但是:

ptr->Name = "Bob";
显然会影响原始对象。

当您“按引用传递”时,实际上是在传递引用的副本,因此将引用设置为指向另一个对象(或null)不会影响原始引用。但是,如果通过取消引用指针副本来更改对象的属性,则调用方将看到这些更改

如果您想真正通过引用传递并使kill方法工作,可以添加
ref
关键字:

public void Kill(ref Person p)
{
    p = null;
}
当您“按引用传递”时,实际上是在传递引用的副本,因此将该引用设置为指向另一个对象(或null)不会影响原始引用。但是,如果通过取消引用指针副本来更改对象的属性,则调用方将看到这些更改

如果您想真正通过引用传递并使kill方法工作,可以添加
ref
关键字:

public void Kill(ref Person p)
{
    p = null;
}

参数Person p是对对象的引用。当您将其置零时-您只是将引用置零,而不是将对象置零。因为
p
是被调用方法的局部变量。您所做的只是将局部变量的引用改为null,而不是传入的person对象。C#中的所有参数都是按值传递的,除非它们特别标记为
ref
out
。对于结构,结构的全部内容是传递的值。如果对其进行修改,所做的更改不会影响原件,因为您修改了副本。对于类,只传递对对象的引用,但该引用是按值传递的。重新指定引用的副本不会影响原始副本。但是,您可以操作对象的内容,因为原始引用和复制的引用都指向同一对象。您只需将引用设置为null,而不更改现有引用处的数据。假设p是一个可以放置块的盒子。将p设置为null会将p中的块放在一边,但它不会对p中以前的块做任何操作。参数Person p是对对象的引用。当您将其置零时-您只是将引用置零,而不是将对象置零。因为
p
是被调用方法的局部变量。您所做的只是将局部变量的引用改为null,而不是传入的person对象。C#中的所有参数都是按值传递的,除非它们特别标记为
ref
out
。对于结构,结构的全部内容是传递的值。如果对其进行修改,所做的更改不会影响原件,因为您修改了副本。对于类,只传递对对象的引用,但该引用是按值传递的。重新指定引用的副本不会影响原始副本。但是,您可以操作对象的内容,因为原始引用和复制的引用都指向同一对象。您只需将引用设置为null,而不更改现有引用处的数据。假设p是一个可以放置块的盒子。将p设置为null会将p中的块放在一边,但它不会对p中以前的块做任何处理。