views:

132

answers:

5

I am having to deal with raw bytes in a project and I need to basically do something like this

byte[] ToBytes(){
  byte[] buffer=new byte[somelength];
  byte[] tmp;
  tmp=BitConverter.GetBytes(SomeShort);
  buffer[0]=tmp[0];
  buffer[1]=tmp[1];
  tmp=BitConverter.GetBytes(SomeOtherShort);
  buffer[2]=tmp[0];
  buffer[3]=tmp[1];
}

I feel like this is so wrong yet I can't find any better way of doing it. Is there an easier way?

A: 

You can make your code a little shorter by using Array.Copy, but no there isn't any GetBytes overload or equivalent in BitConverter that puts the bytes directly into your buffer.

Maybe BinaryWriter on a MemoryStream is what you want?

Note that by adopting the API conventions of BitConverter which you don't like, you're causing the same problem for users of your class. Instead, write a method which accepts a BinaryWriter and serializes your class into it, this extends nicely when your class is embedded in some other object.

Ben Voigt
Not an answer.. should've been a comment.. plus you have the rep to fix it.. (btw, I didn't downvote you)
Earlz
True, I guess I shouldn't post an answer while I'm still writing it. I use ninja edits way too much and sometimes people see a half-answer.
Ben Voigt
+3  A: 

You don't need to initialize tmp to a new array. BitConverter.GetBytes creates a new array and returns it for you. There's not much you can do about GetBytes but you can use methods like Buffer.BlockCopy to simplify the copy operation.

If you're not doing this in a performance-critical piece of code, you can go a bit LINQy and do things like:

IEnumerable<byte> bytes = BitConverter.GetBytes(first);
bytes = bytes.Concat(BitConverter.GetBytes(second));
bytes = bytes.Concat(BitConverter.GetBytes(third));
// ... so on; you can chain the calls too
return bytes.ToArray();
Mehrdad Afshari
Well, is performance intense.. as in called in a very tight loop multiple times..
Earlz
@Earlz: All the more reason not to use the same broken interface that BitConverter has, because now the loop calling your GetBytes is faced with the exact same problem.
Ben Voigt
Well, we ended up just doing it the hardware and using BlockCopy to help us.. Linq is just too slow in this case..
Earlz
s/hardware/hard way
Earlz
@Mehrdad, sorry I gave away the accepted answer, but I later converted from this code to his code and it is much much cleaner. And if it takes few extra microseconds, then it's not *that* performance critical..
Earlz
+2  A: 

BinaryWriter is very efficient:

    byte[] ToBytes() {
        var ms = new MemoryStream(somelength);
        var bw = new BinaryWriter(ms);
        bw.Write(SomeShort);
        bw.Write(SomeOtherShort);
        return ms.ToArray();
    }
Hans Passant
But you need to Flush it.
SLaks
Lots of MemoryStream methods are a no-op. Flush() and Dispose() are not necessary. You can call them if you prefer, the JIT optimizer will just remove the call.
Hans Passant
I upvoted this because I may try it and see if it works better..
Earlz
A: 

If you know the size beforehand (have a set of value types) you could use a struct and assign your values in the struct. Then use unsafe code to copy the raw bytes. I would still advise against it unless it's really necessary for speed purposes. And you might think it's painful :)

private struct MyStruct
{
    public short A;
    public short B;

    public MyStruct(short a, short b)
    {
        A = a;
        B = b;
    }
}

private unsafe byte[] UnsafeStruct(MyStruct myStruct)
{
    byte[] buffer = new byte[4]; // where 4 is the size of the struct
    fixed (byte* ptr = buffer)
    {
        *((MyStruct*)ptr) = myStruct;
    }
    return buffer;
}
Mikael Svenson
A: 

Just bit-shift...

buffer[0]=(byte)SomeShort;
buffer[1]=(byte)(SomeShort >> 8);
buffer[2]=(byte)SomeOtherShort;
buffer[3]=(byte)(SomeOtherShort >> 8);

This also means you are in complete control of the endian-ness (in this case, little-endian)

Marc Gravell
Heh, I know I can do that but thats even more tedious...
Earlz