(C#) 如何按值类型而不是引用类型复制类?

4

请看以下代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyClass
{
    public int myNumber;
}

public class Test : MonoBehaviour
{
    MyClass class1 = new MyClass();
    MyClass class2 = new MyClass();

    void Start()
    {
        class1.myNumber = 1;
        class2 = class1;
        class2.myNumber = 2;

        Debug.Log(class1.myNumber); //output: 2 (I'd want it to output 1!!!)
    }
}

如果我理解正确的话,在C#中,类是引用类型而不是值类型,因此这种行为是期望的。
但是,我该怎么做才能避免这种情况发生?我该如何进行正常的值赋值而不会将两个类"链接"在一起?

我意识到我可以用以下代码替换第18行:

class2.myNumber = class1.myNumber;

这样会达到我想要的效果(因为我正在分配一个值类型而不是引用类型),但对于我的情况来说有点不方便... 在我的真实脚本中,该类具有多个子元素,我需要将它们复制到许多不同的位置。

有没有一种一行代码的方法可以将一个类复制到一个新的类中,而不是通过引用与原始类链接,而是创建一个独立的新类?


使用 struct 是否可行? - rhughes
1
我对C#不是很熟悉,但它与Java非常相似。因此,请参阅https://learn.microsoft.com/en-us/dotnet/api/system.object.memberwiseclone?view=netframework-4.8。 - jiveturkey
@rhughes 这很有趣。与类相比有什么区别?除了它是值类型而不是引用类型,它的行为方式是否相同? - man-teiv
@InBetween 其实,对于我的脚本来说,其中两个类中的一个不需要改变时间,而另一个需要... 有没有办法只让一个类是不可变的? - man-teiv
如果它不会改变,就没有必要做任何事情,即使它不是不可变的,你也不会遇到你所问的问题。关于使类型不可变或可变,这完全取决于它的实现方式,它不是你可以在任何给定的类型或项目上打开或关闭的选项。如果实现不是你自己的,那么就没有办法使可变类型变为不可变;你需要以这种方式设计它。 - InBetween
显示剩余3条评论
3个回答

1
C#有一种叫做结构体的东西,它基本上是类的轻量级版本,是值类型。如果您需要特定的值类型,则可以使用结构体而不是类。
主要区别在于,结构体不需要使用“New”分配进行实例化,它们不能继承自另一个结构体或类,并且不能用作另一个类的基础。

2
结构体仍然可以具有引用类型属性,因此仅使用结构体并不是完整的答案。 - Crowcoder
@Crowcoder,您能详细说明一下吗?哪些属性仍然具有引用类型? - man-teiv
1
@Francesco 他的意思是改成结构体并不是一般性的解决方案。如果一个结构体持有可变引用类型对象的引用,则对该对象的更改将被所有给定值类型的副本"看到",而这些副本具有按值复制的语义独立。 - InBetween
1
在 .Net 中,类和结构的行为有显著的差异。仅仅为了避免 .Net 处理引用类型和值类型的方式而将类型更改为结构并不是一个好的设计决策。在采取这种方法之前,请确保您充分理解所做出的权衡。从这里开始阅读,并继续查看 StackOverflow 上关于常见的 C# 类与结构问题。 - Patrick Tucci

1

谢谢@jiveturkey,我接受了你的答案,因为它是正确的,在示例脚本中它确实有效。但是,为了一切神圣的爱,对于我的主要脚本,它却不起作用!我会继续研究,但我会朝这个方向去。只是为了确认一下,如果我的类只有string、int和int[]类型,我可以简单地使用ShallowCopy吗? - man-teiv
我相信这就是你想要的。不过请再检查一下字符串,它可能是一个对象而不是基本类型。 - jiveturkey
我想我找到了我的问题。显然,数组是引用类型。我正在尝试重新调整DeepCopy方法,看看是否可以适应它们。 - man-teiv

0

这个怎么样?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyClass
{
    public int myNumber;
}

public class Test : MonoBehaviour
{
    MyClass class1 = new MyClass();
    MyClass class2 = new MyClass();

    private void Start()
    {
        class1.myNumber = 1;
        class2 = GetClassCopy(class1);
        class2.myNumber = 2;
        Debug.Log(class1.myNumber); // output:1
    }

    private MyClass GetClassCopy(MyClass source)
    {
        MyClass result = new MyClass();
        result.myNumber = source.myNumber;
        return result;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接