Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.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 - Fatal编程技术网

C# 如何制作数组的浅拷贝?

C# 如何制作数组的浅拷贝?,c#,.net,C#,.net,我将二维数组作为属性传递给我的用户控件。我将这些值存储在另一个二维数组中: int[,] originalValues = this.Metrics; 稍后,我将更改this.Metrics中的值。但是现在如果我从originalValues中检索值,我会从this.Metrics中获取更改后的值。如何复制this.Metrics的元素,而不只是获取数组的引用?您可以克隆一个数组,从而复制它: int[,] originalValues = (int[,])this.Metrics.Clone

我将二维数组作为属性传递给我的用户控件。我将这些值存储在另一个二维数组中:

int[,] originalValues = this.Metrics;

稍后,我将更改
this.Metrics
中的值。但是现在如果我从originalValues中检索值,我会从
this.Metrics
中获取更改后的值。如何复制this.Metrics的
元素,而不只是获取数组的引用?

您可以克隆一个数组,从而复制它:

int[,] originalValues = (int[,])this.Metrics.Clone();

您需要创建一个新数组。然后需要手动将每个元素的值复制到新数组中。在给出的示例中,您要做的是创建两个数组变量,它们都引用相同的数组

克隆方法的问题在于它是浅拷贝。在这种情况下,因为您使用的是
int
,所以不重要。然而,如果您有一个类数组,那么ICLonable接口的定义会使克隆的深度变得模糊不清

想象一下,如果你有一个类,它的属性是其他类,它的属性是其他类。clonable接口未说明是否也将克隆子成员。此外,许多人对预期的行为有不同的看法


因此,这就是为什么通常建议定义两个接口,
IShallowCopy
IDeepCopy
如果要复制的对象是数组,则可以使用:

Array.Copy(sourceArray, destinationArray, sourceArray.Count)

这将为您的目标阵列提供一个单独的原始阵列副本。

我不知道这是从哪里获得的,但这对我来说很有用

public static class GenericCopier<T>    //deep copy a list
    {
        public static T DeepCopy(object objectToCopy)
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(memoryStream, objectToCopy);
                memoryStream.Seek(0, SeekOrigin.Begin);
                return (T)binaryFormatter.Deserialize(memoryStream);
            }
        }
    }
publicstatic类GenericCopier//深度复制列表
{
公共静态T DeepCopy(对象对象复制)
{
使用(MemoryStream MemoryStream=new MemoryStream())
{
BinaryFormatter BinaryFormatter=新的BinaryFormatter();
序列化(memoryStream,objectToCopy);
memoryStream.Seek(0,SeekOrigin.Begin);
返回(T)二进制格式化程序。反序列化(memoryStream);
}
}
}

问题的关键在于:

在那里,我将这些值存储在另一个二维数组中

这实际上是不准确的。您没有创建新数组;您正在将
原始值
变量设置为同一数组。有关更详细的说明,请参见下文


在对的评论中表达的混乱是由于“深度复制”一词的某些不确定性造成的

在复制对象时,有深层复制和浅层复制

深度复制涉及对属于某个对象的所有数据进行复制,这意味着如果该对象包含自身复杂的成员(例如,用户定义引用类型的实例),则这些对象也必须进行深度复制(连同其所有成员,依此类推)

浅层复制只需将所有字段从一个对象复制到另一个对象,这意味着如果对象包含引用类型,则只需复制引用(因此复制的引用将指向相同的对象)

对于您发布的代码:

int[,] originalValues = this.Metrics;
。。。实际上,根本没有复制任何对象。您所做的只是复制一个引用,将
this.Metrics
(一个引用)的值分配给变量
originalValues
(也是一个引用,分配给同一个数组)。这与简单的赋值基本相同,如下所示:

int x = y; // No objects being copied here.
StringBuilder[,] builders = GetStringBuilders();
StringBuilder[,] builderCopies = (StringBuilder[,])builders.Clone();
现在,
Array.Clone
方法实际上是一个浅拷贝。但正如Pieter所指出的,整数数组的“浅”副本和“深”副本实际上没有区别,因为整数不是复杂的对象

如果你有这样的东西:

int x = y; // No objects being copied here.
StringBuilder[,] builders = GetStringBuilders();
StringBuilder[,] builderCopies = (StringBuilder[,])builders.Clone();

…,您将得到一个全新的数组(是的,是一个副本),但其中包含所有相同的
StringBuilder
对象(因此是一个浅副本)。这就是深度复制与浅复制的关系;如果您想要一个新数组,其中包含来自
builders
的所有
StringBuilder
对象的副本,则需要进行深度复制。

您可以使用LINQ对1d数组进行深度复制

var array = Enumerable.Range(0, 10).ToArray();
var array2 = array.Select(x => x).ToArray();
array2[0] = 5;
Console.WriteLine(array[0]);  // 0
Console.WriteLine(array2[0]); // 5

对于2d数组,这将不起作用,因为2d数组不实现IEnumerable。

如果要深度复制引用类型的数组,可以使用以下方法:

为类实现
IClonable
iterface,并将其中的所有值类型字段深度复制到另一个构造的对象中

class A: ICloneable {
     int field1;
     public object Clone()
        {
            A a= new A();
            //copy your fields here 
            a.field1 = this.field1;
            ...
        }
}
然后,您可以使用

A[] array1 = new A[]{....};
A[] array2 = array1.Select(a => a.Clone()).ToList();

IClonable很好,但除非您的顶级克隆类型中的每种类型都是
IClonable
,否则您最终会得到引用,好吧

基于此,除非您想遍历对象并克隆其中的每个对象,否则这似乎是最简单的方法

它很简单,保证了与原始文件中深层对象的引用完全分离:

using Newtonsoft.Json;

private T DeepCopy<T>(object input) where T : class
{
    var copy = JsonConvert.SerializeObject((T)input); // serialise to string json object
    var output = JsonConvert.DeserializeObject<T>(copy); // deserialise back to poco
    return output;
}
使用Newtonsoft.Json;
私有T DeepCopy(对象输入),其中T:class
{
var copy=JsonConvert.SerializeObject((T)input);//序列化为字符串json对象
var output=JsonConvert.DeserializeObject(copy);//反序列化回poco
返回输出;
}
用法:

var x = DeepCopy<{ComplexType}>(itemToBeCloned);
var x=DeepCopy(itemToBeCloned);
其中,
ComplexType
是任何想要脱离引用的内容

它接受任何类型,将其字符串化,然后反字符串化为新副本

最佳使用示例:
如果您选择了一个复杂类型作为lambda查询的结果,并且希望在不影响原始结果的情况下修改结果。

这里有一个快速解决方案,它几乎与这里的一些答案类似,但其中提到了

我有只包含参考值的POCO

public class MyPoco {
    public int x { get; set; }
    public int y { get; set; }
    public int z { get; set; }

    // Add a "Clone" method.
    public MyPoco Clone() {
        return (MyPoco)this.MemberwiseClone();
    }
}
然后使用LINQ构建一个新阵列