How to convert a bunch of primitive value types to byte array efficiently in .NET in Silverlight compatible manner?
Observe the following .NET type:
public class X
{
public DateTime Timestamp {get;set;}
public double Value {get;set;}
public double Min {get;set开发者_StackOverflow中文版;}
public double Max {get;set;}
}
I need to convert an array of N elements of X to a single byte array and vice versa efficiently and the code must be Silverlight compatible (meaning forget about the binary serialization, be it efficient or not).
My solution is:
public void GetState(SerializationInfo info)
{
var stream = new MemoryStream();
var buf = BitConverter.GetBytes(Count);
stream.Write(buf, 0, buf.Length);
foreach (var item in this)
{
buf = BitConverter.GetBytes(item.Timestamp.Ticks);
stream.Write(buf, 0, buf.Length);
buf = BitConverter.GetBytes(item.Value);
stream.Write(buf, 0, buf.Length);
buf = BitConverter.GetBytes(item.Min);
stream.Write(buf, 0, buf.Length);
buf = BitConverter.GetBytes(item.Max);
stream.Write(buf, 0, buf.Length);
}
info.AddValue("Data", stream.ToArray());
}
public void SetState(SerializationInfo info)
{
var data = info.GetValue<byte[]>("Data");
int count = BitConverter.ToInt32(data, 0);
Capacity = count;
int offset = sizeof(int);
while (count-- > 0)
{
Add(new ExtendedNormalizedSample(
new DateTime(BitConverter.ToInt64(data, offset)),
BitConverter.ToDouble(data, offset += sizeof(long)),
BitConverter.ToDouble(data, offset += sizeof(double)),
BitConverter.ToDouble(data, offset += sizeof(double))));
offset += sizeof(double);
}
}
(Ignore the SerializationInfo stuff - irrelevant for the question)
Anyway, what I do not like about my solution is the abundance of byte[] arrays created during the serialization. I mean, every call to BitConverter.GetBytes
returns a new byte array and although, creating new byte arrays is cheap in .NET, but still, as a former C++ developer, this seems to be an awful waste to use a new byte array each time, whereas a single byte array can be reused.
Can anyone suggest a better solution (remember, it must be Silverlight compatible, so do not propose unsafe code).
Thanks.
The DateTime
Ticks
could be encoded as an integer via shift operations etc. The float
- you might try using a union to swap for int
, and then encode the int
with shift operations:
[StructLayout(LayoutKind.Explicit)]
struct MyUnion
{
[FieldOffset(0)]
private int i;
[FieldOffset(0)]
private float f;
public static int ToInt32(float value) {
MyUnion u = new MyUnion();
u.f = value;
return u.i;
}
public static float ToSingle(int value) {
MyUnion u = new MyUnion();
u.i = value;
return u.f;
}
}
Then if you have an existing Stream
or byte[]
you can encode (depending on your chosen endianness) something like:
int iValue = MyUnion.ToInt32(fValue);
int offset = ...;
...
buffer[offset++] = (byte)iValue;
buffer[offset++] = (byte)(iValue >> 8);
buffer[offset++] = (byte)(iValue >> 16);
buffer[offset++] = (byte)(iValue >> 24);
精彩评论