Author | Message | Time |
---|---|---|
mentalCo. | I'm trying to copy my ArrayList into a byte buffer. For some reason when I try to do this I get this error: [quote] An unhandled exception of type 'System.InvalidCastException' occurred in mscorlib.dll Additional information: At least one element in the source array could not be cast down to the destination array type. [/quote] Here's my code... [code] byte[] bytSend=new byte[alBuffer.Count + 4]; bytSend[0] = 0xFF; bytSend[1] = id; Array.Copy(BitConverter.GetBytes((short)(alBuffer.Count + 4)), 0, bytSend, 2, 2); alBuffer.CopyTo(0, bytSend, 4, alBuffer.Count); tcpPRIV.GetStream().Write(bytSend, 0, bytSend.Length); [/code] | December 20, 2004, 9:23 PM |
Myndfyr | I'm not sure if this is because you're using a value type inside of a reference type-list. If you're using .NET 2.0 Beta 1, I highly recommend using System.Collections.Generics.List<byte> over an ArrayList. If not, you will likely have to iterate over each item in the ArrayList instead of using .CopyTo(int, byte[], int, int) and manually cast. This is because when you add a value type to an ArrayList, the framework has to box the value into a reference wrapper. Apparently, the .CopyTo doesn't try to unbox. Let's look: [code] .method public hidebysig newslot virtual instance void CopyTo(int32 index, class System.Array 'array', int32 arrayIndex, int32 count) cil managed { // Code size 73 (0x49) .maxstack 5 IL_0000: ldarg.0 IL_0001: ldfld int32 System.Collections.ArrayList::_size IL_0006: ldarg.1 IL_0007: sub IL_0008: ldarg.s count IL_000a: bge.s IL_001c IL_000c: ldstr "Argument_InvalidOffLen" IL_0011: call string System.Environment::GetResourceString(string) IL_0016: newobj instance void System.ArgumentException::.ctor(string) IL_001b: throw IL_001c: ldarg.2 IL_001d: brfalse.s IL_0038 IL_001f: ldarg.2 IL_0020: callvirt instance int32 System.Array::get_Rank() IL_0025: ldc.i4.1 IL_0026: beq.s IL_0038 IL_0028: ldstr "Arg_RankMultiDimNotSupported" IL_002d: call string System.Environment::GetResourceString(string) IL_0032: newobj instance void System.ArgumentException::.ctor(string) IL_0037: throw IL_0038: ldarg.0 IL_0039: ldfld object[] System.Collections.ArrayList::_items IL_003e: ldarg.1 IL_003f: ldarg.2 IL_0040: ldarg.3 IL_0041: ldarg.s count IL_0043: call void System.Array::Copy(class System.Array, int32, class System.Array, int32, int32) IL_0048: ret } // end of method ArrayList::CopyTo [/code] Of interest to us is IL_0039 -- it goes to object[]. This is from Array.Copy(Array, int, Array, int, int): [code] .method public hidebysig static void Copy(class System.Array sourceArray, int32 sourceIndex, class System.Array destinationArray, int32 destinationIndex, int32 length) cil managed internalcall { } // end of method Array::Copy [/code] Note the internalcall flag -- it's part of the CLR, so unfortunately we can't look deeper. Since we didn't get anything answered, I'll stand by my original assumption that there is an unboxing problem. You can go through and manually cast each item to byte, but apparently value types don't automatically cast. BTW, an ArrayList is a bad object to store bytes in. Figure this: For every byte you store (one byte of memory), you have to have a four-byte box of it. There will be 3 bytes also used for padding, since in this case, when storing it as an object you'll be boxing. Then you've got a four-byte reference to the next node in the List (check out an implementation of a singly-linked list on Google). So you're using 12 bytes for every one byte you're storing. A System.Collections.Generic.List<byte> eliminates the boxing wrapper, and you go to 8 bytes per byte to store; not as bad, but still quite a bit. A System.IO.MemoryStream is a better structure to use. See this buffer for an alternative. | December 20, 2004, 9:46 PM |