Is it right to copy C # structures with (byte) arrays in them?

From what I understand, when assigning a struct variable to another, the first is usually copied instead of creating a link:

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); } 

This works fine, output:

 1 2 

However, if I have a byte [] inside my structure, this behavior changes:

 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]); } 

This is the conclusion:

 2 2 

How can i avoid this? I really need to work with a copy of the whole structure, including any byte arrays.

Thanks! ♪


Edit: Thanks for your help! To deep copy my structure, Im now uses this code:

 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; } 

It must be called like this:

 MYSTRUCT1 test2 = (MYSTRUCT1)deepCopyStruct(test1, typeof(MYSTRUCT1)); 

Everything seems to be working fine, although Im aware that this is dirty code.

However, since there are more than 50 byte[] several other structures in them that work with, there is too much work to write Copy() / Clone() methods for each of them.

Suggestions for better code are, of course, very welcome.

+6
arrays reference c # struct copy
source share
7 answers

I can not find the link, but in the second case, you just copy the address of the array, not the entire array.

You need to make a deep copy where you will also copy the contents of the array.

+2
source share

You will need to create a Clone method to make a deep copy of the structure elements:

 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 }; } } 
+3
source share

This causes an overload for the struct copy method, which does not require pouring the results:

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

You call it this way:

 MYSTRUCT1 x = RawDeserialize<MYSTRUCT1>(...); 

You can even use var :

 var x = RawDeserialize<MYSTRUCT1>(...); 
+2
source share

If you want the structure to encapsulate the array by value (or at least behave as if it did), so copying the structure will copy the array, you have four options that I can see:

  • If the array has a fixed size, declare the struct as `unsafe` and use the` fixed` array in it. The `fixed` array is stored as part of the contained structure, so copying the structure will copy the array.
  • If the array has a small fixed size, but you do not want to use fixed code, you can declare a field for each element of the array, and then write an indexed property that reads or writes one of the fields of the structure if necessary. This is probably the best approach if the array has about 4 elements, but it would be impractical if it has hundreds or thousands.
  • A structure may contain a private reference to an array that will never be modified; any operation that will modify the array must make a copy of the array, modify this copy and then overwrite the private link with a link to the new array (follow the steps in this order ). This approach can be effective if the structure is widely copied, but the array is rarely modified.
  • Write a class that behaves like an immutable array and that contains a method that will generate a new instance if it is given an old instance, the index of the element, and the new value that will be stored in this element. The structure pointer will look something like the one shown below; real difficulty would be in the classroom.
 byte this[int n] { get {return myContents[n];} set {myContents = myContents.WithValue(n, value);} } 

Approach No. 4 with a suitable object class class can achieve O (Lg (N)) performance both for reading and for writing made in random order, or it can be able to achieve O (1) performance for reading and writing (for example, the method "write") can simply add each index and value to the linked list of updates until the number of updates exceeds the size of the array or tries to read an element, and then can create a new array with all applicable updates: such a class will execute tsya slowly, if it turns to read and write, but the total time of N updates, followed by N-reading will be O (N), which means that the average time to update or reading O (1).

+2
source share

Yes, but byte[] is a reference type. Therefore, only a link (pointer) is stored in the structure (structure is the type of value). When a structure is copied, only the link is copied.

You need to create a new byte[] and copy the data.

+1
source share

To copy all byte[] into a class, you can use reflection.

 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; } } 

Using:

 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]); 

Gives: "1, 2, 3, 2"

Note that I used properties instead of elements for arrays, but you can also use reflection for member variables.

0
source share

One smart workaround , borrowed from here :

 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; } } 

In addition to the safe type due to the use of the template, as well as the preservation of two functions, you need to associate the SerializableAttribute with your struct (or classes); CLR binary (de) serialization is much better than blind copying raw bytes, I think:

 [Serializable] struct test { public int[] data; } 
0
source share

All Articles