C# 为什么对象会自动通过引用传递?

C# 为什么对象会自动通过引用传递?,c#,clone,pass-by-reference,pass-by-value,shallow-copy,C#,Clone,Pass By Reference,Pass By Value,Shallow Copy,在C#的按引用传递和按值传递概念的背景下,我有一个关于深度和浅层复制的一般性问题: 在C#中,需要显式创建接受指针/引用的方法,以便能够将这些指针/引用传递给方法。但是,至少作为参数传递给方法/构造函数的对象的行为与其他对象不同。如果没有按照此处所述进行额外的克隆,则它们似乎总是通过引用传递: 为什么对象会自动通过引用传递? 在这些情况下,强制执行克隆过程而不是像int、double、boolean等那样处理对象有什么特别的好处吗? 下面的代码示例说明了我的意思: using System;

在C#的按引用传递和按值传递概念的背景下,我有一个关于深度和浅层复制的一般性问题:

在C#中,需要显式创建接受指针/引用的方法,以便能够将这些指针/引用传递给方法。但是,至少作为参数传递给方法/构造函数的对象的行为与其他对象不同。如果没有按照此处所述进行额外的克隆,则它们似乎总是通过引用传递:

为什么对象会自动通过引用传递? 在这些情况下,强制执行克隆过程而不是像int、double、boolean等那样处理对象有什么特别的好处吗?

下面的代码示例说明了我的意思:

using System;

public class Entry
{

    public class MyColor
    {
        public int r = 0;
        public int g = 0;
        public int b = 0;
        public double a = 1;

        public MyColor (int r, int g, int b, double a)
        {
            this.r = r;
            this.g = g;
            this.b = b;
            this.a = a;
        }
    }

    public class A
    {
        public int id;
        public MyColor color;
        public MyColor hiddenColor;

        public A (int id, MyColor color)
        {
            this.id = id;
            this.color = color;
        }
    }

    static void Main(string[] args)
    {
        int id = 0;
        MyColor col = new MyColor(1, 2, 3, 1.0);

        A a1 = new A(id, col);
        A a2 = new A(id, col);

        a1.hiddenColor = col;
        a2.hiddenColor = col;

        a1.id = -999;
        id = 1;
        col.a = 0;

        Console.WriteLine(a1.id);
        Console.WriteLine(a2.id);

        Console.WriteLine(a1.color.a);
        Console.WriteLine(a2.color.a);

        Console.WriteLine(a1.hiddenColor.a);
        Console.WriteLine(a2.hiddenColor.a);
    }
}
这导致:

-999
0
0
0
0
mycl
的实例始终通过引用传递,而其他参数则通过值传递。我必须在类
MyColor
A
中实现iClonable。另一方面,“ref”语句出现在C#中,它应该用于显式地允许并通过引用传递

欢迎您的建议

为什么对象会自动通过引用传递

他们不是

在这些情况下,强制执行克隆过程而不是像int、double、boolean等那样处理对象有什么特别的好处吗

引用类型没有“克隆过程”,只有值类型

我认为你混淆了不同的概念:

  • 值类型与引用类型

    对于值类型(如基本数字类型、枚举和结构,如
    DateTime
    ),变量的值是对象本身。将变量指定给另一个(或通过值将其作为参数传递)将创建对象的副本

    对于引用类型(如
    对象
    字符串
    、类(非结构)等),变量的值是对对象的引用。将变量指定给另一个(或通过值将其作为参数传递)将创建引用的副本,因此它仍然引用同一个对象实例

  • 通过值传递参数与通过引用传递参数

    按值传递参数意味着传递值的副本。根据它是值类型还是引用类型,这意味着对象本身的副本,还是引用的副本。如果被调用方修改作为参数传递的值类型的成员,调用方将看不到更改,因为被调用方正在处理副本。另一方面,如果被调用方修改作为参数传递的引用类型的成员,调用方将看到更改,因为被调用方和调用方都有对同一对象实例的引用

    通过引用传递参数意味着将引用传递给变量(可以是值类型或引用类型的变量)。不复制该值:它在调用方和被调用方之间共享。因此,被调用方所做的任何更改(包括为参数赋值)都将被调用方看到

    除非另有规定(使用
    ref
    out
    关键字),否则所有参数均按值传递,包括引用类型。只是对于引用类型,传递的值是一个引用,但它仍然是通过值传递的


我建议您阅读Jon Skeet的文章以获得更好的解释。

所有方法参数都是按值传递的,除非您明确指定它们应该使用
ref
out
关键字按引用传递。这意味着,如果将变量传递给方法参数,则会复制变量的内容并将其传递给方法

如果变量是值类型,基本上意味着结构,那么该变量包含一个对象,因此该对象被复制。如果变量是引用类型,这基本上意味着
,那么该变量包含对对象的引用,以便复制引用


如果将参数声明为
ref
out
,则会创建对变量的引用,并将其传递给方法。如果变量包含对象,则创建对该对象的引用;如果变量包含引用,则创建对该引用的引用。

我将重新表述您的问题:我们为什么需要类?我们就不能只有结构吗


并非所有对象都可以安全复制。例如,您不能从逻辑上复制
文件流
按钮
。这些对象具有标识,您希望所有代码都引用唯一的对象。

类或接口类型(统称为“引用类型”)的变量、参数或字段不包含类对象;它包含一个对象标识符。同样,引用类型的数组不包含对象;它保存对象标识符

即使.NET中的对象没有任何与之相关联的人类可读标识符,也可以像这样对它们进行推理:如果在程序执行过程中至少创建了一些对象(例如592个),那么恰好有一个对象将是创建的第592个对象;一旦创建了第592个对象,就不会有其他对象成为第592个对象。没有办法找出哪个对象是592,但是如果保存对592对象的引用的变量作为非引用参数传递给某个方法,那么当该方法返回时,它将继续保存对592对象的引用。如果对象#592是对红色的
Car
实例的引用,则局部变量
myCar
保存“objectid#592”,并调用方法
PaintCar(myCar)
,则该方法将接收
对象#592“
。如果该方法将汽车漆成蓝色,则当它返回时,
myCar
将保留“Object#592”,这将识别