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

正确复制包含(字节)数组的C#结构?

正确复制包含(字节)数组的C#结构?,c#,arrays,reference,copy,struct,C#,Arrays,Reference,Copy,Struct,据我所知,将结构变量赋值给另一个结构变量时,通常会复制第一个结构变量,而不是创建引用: public struct MYSTRUCT1 { public byte val1; } // (...) public DoSomething() { MYSTRUCT1 test1; test1.val1 = 1; MYSTRUCT1 test2 = test1; test2.val1 = 2; Console.WriteLine(test1.val1)

据我所知,将结构变量赋值给另一个结构变量时,通常会复制第一个结构变量,而不是创建引用:

public struct MYSTRUCT1
{
    public byte val1;
}
// (...)
public DoSomething() {
    MYSTRUCT1 test1;
    test1.val1 = 1;
    MYSTRUCT1 test2 = test1;
    test2.val1 = 2;

    Console.WriteLine(test1.val1);
    Console.WriteLine(test2.val1);
}
这工作正常,输出为:

1
2
但是,如果我的结构中有一个字节[],则此行为会发生变化:

public struct MYSTRUCT1
{
    public byte[] val1;
}
// (...)
public DoSomething() {
    MYSTRUCT1 test1;
    test1.val1 = new byte[0x100];
    test1.val1[0] = 1;
    MYSTRUCT1 test2 = test1;
    test2.val1[0] = 2;

    Console.WriteLine(test1.val1[0]);
    Console.WriteLine(test2.val1[0]);
}
这是输出:

2
2
我怎样才能避免这种情况?我确实需要使用完整结构(包括任何字节数组)的副本

谢谢大家!!♪


编辑:谢谢你的帮助! 为了深入复制我的结构,我现在使用以下代码:

public static object deepCopyStruct(object anything, Type anyType)
{
    return RawDeserialize(RawSerialize(anything), 0, anyType);
}

/* Source: http://bytes.com/topic/c-sharp/answers/249770-byte-structure */
public static object RawDeserialize(byte[] rawData, int position, Type anyType)
{
    int rawsize = Marshal.SizeOf(anyType);
    if (rawsize > rawData.Length)
        return null;
    IntPtr buffer = Marshal.AllocHGlobal(rawsize);
    Marshal.Copy(rawData, position, buffer, rawsize);
    object retobj = Marshal.PtrToStructure(buffer, anyType);
    Marshal.FreeHGlobal(buffer);
    return retobj;
}

/* Source: http://bytes.com/topic/c-sharp/answers/249770-byte-structure */
public static byte[] RawSerialize(object anything)
{
    int rawSize = Marshal.SizeOf(anything);
    IntPtr buffer = Marshal.AllocHGlobal(rawSize);
    Marshal.StructureToPtr(anything, buffer, false);
    byte[] rawDatas = new byte[rawSize];
    Marshal.Copy(buffer, rawDatas, 0, rawSize);
    Marshal.FreeHGlobal(buffer);
    return rawDatas;
}
必须这样称呼它:

MYSTRUCT1 test2 = (MYSTRUCT1)deepCopyStruct(test1, typeof(MYSTRUCT1));
MYSTRUCT1 x = RawDeserialize<MYSTRUCT1>(...);
虽然我知道这是一个肮脏的代码,但它似乎工作得很好

但是,由于我正在使用的结构中有50多个
字节[]
其他几个结构,因此为每个结构编写
Copy()
/
Clone()
方法的工作量太大了


当然,我们非常欢迎对更好代码的建议。

我找不到参考,但在第二种情况下,您只是复制数组的地址,而不是整个数组


您需要在复制数组内容的位置执行深度复制。

您必须创建一个
克隆方法来执行结构成员的深度复制:

public struct MyStruct
{
    public byte[] data;
    public MyStruct Clone()
    {
        byte[] clonedData = new byte[this.data.Length];
        data.CopyTo(clonedData, 0);

        return new MyStruct { data = clonedData };
    }
}

是,但是
字节[]
是引用类型。因此,结构中只存储了一个引用(指针)(结构是值类型)。复制结构时,仅复制引用


您需要创建一个新的
字节[]
并复制数据。

以下是struct copy方法的重载,它不需要强制转换结果:

public static T RawDeserialize<T>(byte[] rawData, int position)
{
    return (T)RawDeserialize(rawData, position, typeof(T));
}

要复制类中的所有
字节[]
,可以使用反射

class ArrayContainer
{
    public byte[] Array1 { get; set; }
    public byte[] Array2 { get; set; }

    public ArrayContainer DeepCopy()
    {
        ArrayContainer result = new ArrayContainer();
        foreach (var property in this.GetType().GetProperties())
        {
            var oldData = property.GetValue(this, null) as byte[];
            if (oldData != null)
            {
                // Copy data with .ToArray() actually copies data.
                property.SetValue(result, oldData.ToArray(), null);
            }
        }

        return result;
    }
}
用法:

ArrayContainer container = new ArrayContainer();
container.Array1 = new byte[] { 1 };
container.Array2 = new byte[] { 2 };
ArrayContainer copy = container.DeepCopy();
copy.Array1[0] = 3;

Console.WriteLine("{0}, {1}, {2}, {3}", container.Array1[0], container.Array2[0], copy.Array1[0], copy.Array2[0]);
给出:“1,2,3,2”


请注意,我对数组使用了属性而不是成员,但您也可以对成员变量使用反射。

一个更聪明的解决方法,借用自:


如果您想让一个结构按值封装一个数组(或者至少像这样),这样复制结构就会复制数组,那么我可以看到四个选择:

  • 如果数组大小固定,请将结构声明为“不安全”,并在其中使用“固定”数组。“fixed”数组存储为包含结构的一部分,因此复制该结构将复制该数组。
  • 如果数组的大小固定,但不想使用固定的代码,则可以为数组的每个元素声明一个字段,然后编写一个索引属性,根据需要读取或写入结构的一个字段。如果数组有大约4个元素,这可能是最好的方法,但是如果数组有数百个或数千个元素,这将是不切实际的。
  • 结构可以保存对数组的私有引用,而数组永远不会被修改;任何修改数组的操作都应该创建数组的副本,修改该副本,然后用对新数组的引用覆盖私有引用(按该顺序执行步骤)。如果广泛复制结构,但很少修改阵列,则此方法可能是有效的。
  • 编写一个行为类似于不可变数组的类,该类包含一个方法,如果给定一个旧实例、一个项索引和一个要存储在该项中的新值,该方法将生成一个新实例。结构索引器的外观如下所示;真正的复杂性在课堂上。
    具有适当设计的对象保持器类的方法#4对于以任意顺序执行的读取和写入可以实现O(Lg(N))性能,或者对于以特定模式(例如“写入”)执行的读取和写入可以实现O(1)性能方法可以简单地将每个索引和值添加到更新的链接列表中,直到更新的数量超过数组的大小或尝试读取某个项,然后可以创建一个应用了所有更新的新数组;如果交替读取和写入该类,则该类的执行速度会很慢,但执行N个更新的总时间es后跟N次读取将是O(N),这意味着每次更新或读取的平均时间将是O(1)。

    这是重载赋值运算符的有效原因吗?哇,如果我有一个包含70字节[]的结构,我必须为它们中的每一个编写自定义代码?@blougsel-是的,你会的,尽管创建这样一个结构不是一个好主意。结构用于小型应用程序(谢谢你的提示。我正在处理几KBs的原始二进制数据,需要以一种方便的方式访问其中的一部分,这就是为什么我要使用这样的结构。否则你会怎么做呢?字节数组对于二进制数据非常方便,你不必将它们放在结构中,你可以将数组放在一个常规类中。顺便说一句,你已经编写了更多的c++比c#,我猜是。Marshal.AllocHGlobal方法:从进程的非托管内存分配内存。[MSDN]sooo.。它不需要强制转换结果,因为它正在强制转换结果???。您不需要强制转换该方法产生的结果。
    ArrayContainer container = new ArrayContainer();
    container.Array1 = new byte[] { 1 };
    container.Array2 = new byte[] { 2 };
    ArrayContainer copy = container.DeepCopy();
    copy.Array1[0] = 3;
    
    Console.WriteLine("{0}, {1}, {2}, {3}", container.Array1[0], container.Array2[0], copy.Array1[0], copy.Array2[0]);
    
    static public T DeepCopy<T>(T obj)
    {
        BinaryFormatter s = new BinaryFormatter();
        using (MemoryStream ms = new MemoryStream())
        {
            s.Serialize(ms, obj);
            ms.Position = 0;
            T t = (T)s.Deserialize(ms);
    
            return t;
        }
    }
    
    [Serializable]
    struct test
    {
        public int[] data;
    }
    
    byte this[int n] {
      get {return myContents[n];}
      set {myContents = myContents.WithValue(n, value);}
    }