1

I need to get the size of variables I'm using to write them to a byte array. However I wish to retain easy refactoring so using something like sizeof(int) doesn't really cut it.

This is a simplified version of what I have now:

public byte[] ToBytes()
{
    int byteIndex = 0;
    byte[] result = new byte[sizeof(byte) + sizeof(byte) + sizeof(long) + RawBytes.Count];
    ...
    BitConverter.TryWriteBytes(new Span<byte>(result, byteIndex, sizeof(long)), TimeStamp)
    byteIndex += sizeof(long);
    ...
    return result;
}

Where TimeStamp is a property of the long type.

If I want to change the type of the TimeStamp variable I now need to modify three parts of this code. As I add more variables it will be even easier to make a mistake.
And it's also not very clear which variable each sizeof() refers to.

Is there a simple solution? Something like sizeof(typeof(TimeStamp))
Or do I need to make a workaround like writing my own sizeof-method with an overload for each type or an is check for each type I want to use?

Though not an answer to my question, @HansPassant suggested using a BinaryWriter and writing to a MemoryStream which will solve the problem at hand.

Ghork
  • 70
  • 8
  • sizeof(long) will obviously refer to the data size of `long` data type – shuberman Oct 17 '19 at 11:40
  • 1
    Can you give us a context? Why are you doing this? – tymtam Oct 17 '19 at 11:41
  • what is `TimeStamp` here? Yes, `sizeof(TimeStamp)` is a "thing" *if* `TimeStamp` is a `struct` (although you shouldn't use it unless it is an "unmanaged" struct, i.e. it contains no references directly or indirectly) - or `Unsafe.SizeOf()` if you don't want to enable `unsafe` at the language level, but without knowledge of what you're doing here, it is hard to offer guidance – Marc Gravell Oct 17 '19 at 11:46
  • I don't want to hard-code "long". I want to be able to change the type in just one place without having to update 50 other places where I might have used sizeof() for that variable. – Ghork Oct 17 '19 at 11:49
  • seems like you are trying to seralize something, when theres something that already does that – BugFinder Oct 17 '19 at 11:50
  • Use reflection to loop over all the properties in the class you want to serialize, get their type, get the size of each type, allocate your array and do your serialization. But that will likely be more overhead than just serializing each field to a byte array and concatenating all those arrays at the end. A possible better idea is to allocate an array of X bytes up-front, then serialize into it - if you run out of space in the array, allocate a new one of 2 * X size that replaces the original array, and repeat as needed. (This is what `List` does internally). – Ian Kemp Oct 17 '19 at 11:51
  • @tymtam I need to write bytes to a byte array for sending on a socket. I'm going to have several different variables that I will write and I might change their types so hard-coding sizeof(byte), sizeof(int), sizeof(long) etc is going to be confusing to read and it will make refactoring the types difficult. – Ghork Oct 17 '19 at 11:54
  • @BugFinder Yeah, but I couldn't find a good way. Most of the time I won't want to serialize the whole object. – Ghork Oct 17 '19 at 12:09
  • One basic way to avoid this kind of code is by using BinaryWriter to write into a MemoryStream. Something like protocol buffers is probably worth a look. – Hans Passant Oct 17 '19 at 12:13
  • @HansPassant A `BinaryWriter` using a `MemoryStream` appears like it would be the solution to my problem, so thank you for that. – Ghork Oct 17 '19 at 12:49

2 Answers2

0

I hope I understand what you try to do. But there is also a solution which does not need the sizeof-Operator. You can define a class and tell the compiler how it should arrange the fields in the memory. One example:

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public class YourClass
{
 public int SomeInteger;

 public byte SomeByte;

 public long Timestamp;
}

In this example, the first four bytes will be SomeInteger, the next byte will be SomeByte, and then will follow 8 bytes for Timestamp. How can then easily convert instances of this class into a byte array: How to convert a structure to a byte array in C#?

Addendum: After reading your last comment, I saw you need a different solution. If you don't want to serialize the whole object always, you could also use a list instead of a byte array:

public byte[] ToBytes()
{
    List<byte> result = new List<byte>();
    // ...
    result.AddRange(BitConverter.GetBytes(timestamp));
    // ...
    return result.ToArray();
}
SomeBody
  • 7,515
  • 2
  • 17
  • 33
0

I don't understand exactly what you want to do.Nevertheless you'll find below an generic implementation possibility.

public byte[] ToBytes<T>()
{
    int instance_layout_bytes = typeof(T).IsValueType ? 
                                Unsafe.Sizeof<T>() : 
                                Marshal.ReadInt32(typeof(T).TypeHandle.Value, 4);

    int byteIndex = 0;
    byte[] result = new byte[instance_layout_bytes  + RawBytes.Count];
    ...
    BitConverter.TryWriteBytes(new Span<byte>(result, byteIndex, instance_layout_bytes), T)
    byteIndex += instance_layout_bytes;
    ...
    return result;
}```
Inspired by :
[Size of managed structures][1]
[sizeof][2]


  [1]: https://stackoverflow.com/questions/2127707/size-of-managed-structures
  [2]: https://learn.microsoft.com/fr-fr/dotnet/csharp/language-reference/operators/sizeof
Tohm
  • 305
  • 1
  • 5
  • I don't know what the implications of unmanaged code are so therefore I've avoided it. Allowing unsafe code `sizeof(TimeStamp)` or `Marshal.SizeOf(typeof(TimeStamp)));` would solve my issue. I need the size of the type of the variable. But I don't want to hard-code the type like: `sizeof(long)` since I would have to write it in multiple places in my code for one variable. Then changing the variable type to i.e. `int` would require I knew which `sizeof(long)` was for this specific variable. – Ghork Oct 17 '19 at 12:22