I want to implement a set of classes, that can be used both with UInt16 and UInt32 type parameters.
The first one represents the header of a telegram, that can be used both with UInt32 and UInt64 data types.
Any non essential fields have been ommitted!
Currently I am working with .NetFramework 4.7.2. and VS 2017. Upgrading to another framework may be an option, but could break other things, like dependencies...
public class Header<T> // where T : struct, IConvertible
{
public Header(T off, T len)
{
Offset = off;
LenData = len;
}
public T Offset;
public T LenData;
public byte[] ToByteArray()
{
byte[] bTemp = new byte[2 * Marshal.SizeOf(typeof(T))];
if (Offset is UInt16)
{
Array.ConstrainedCopy(System.BitConverter.GetBytes(Convert.ToUInt16(Offset)), 0, bTemp, 0, Marshal.SizeOf(typeof(T)));
Array.ConstrainedCopy(System.BitConverter.GetBytes(Convert.ToUInt16(LenData)), 0, bTemp, Marshal.SizeOf(typeof(T)), Marshal.SizeOf(typeof(T)));
}
else if (Offset is UInt32)
{
Array.ConstrainedCopy(System.BitConverter.GetBytes(Convert.ToUInt16(Offset)), 0, bTemp, 0, Marshal.SizeOf(typeof(T)));
Array.ConstrainedCopy(System.BitConverter.GetBytes(Convert.ToUInt16(LenData)), 0, bTemp, Marshal.SizeOf(typeof(T)), Marshal.SizeOf(typeof(T)));
}
else
{
throw new NotSupportedException("Type " + Offset.GetType() + "not supported");
}
return bTemp;
}
}
This class gives me a byte array for the telegram header (2 + 2 bytes for T = UInt16 and 4 + 4 for T = UInt32).
Now I need another class, which uses the header class to build the byte array for the telegram:
class Telegram<T>
{
public Header<T> header;
public Telegram(T offset, byte[] bData)
{
header = new Header<T>(offset,bData.Length)
}
}
On its own, the class works as expected:
static void Main(string[] args)
{
byte[] bData = new byte[16];
// This call works
Header<UInt16> ui16Header = new Header<ushort>(12345, (ushort)bData.Length);
byte[] b0 = ui16Header.ToByteArray();
b0 contains the desired telegram content...
Then i want to create two telegrams (for both supported data types:
// These calls don't work (because of compile error, or
// because of a thrown exception - see below)
Telegram<UInt16> telegram16 = new Telegram<ushort>(7000, bData);
Telegram<UInt32> telegram32 = new Telegram<uint>(70000, bData);
}
The constructor of the class Telegram from above does not compile (cant convert int to T).
After changing the constructor as follows, it can be compiled:
public Telegram(T offset, byte[] bData)
{
object ot = bData.Length;
T len = (T)ot;
header = new Header<T>(offset, len);
}
But this leads to a runtime exception.
Can this problem be solved? I know, that I could simply write two classes that contain all type specific methods themselves, but only the fields in the header are either UInt16 or UInt32
Or would it be the easier way to work with inheritance and interfaces?
In .NET 7+, you can use the new
INumberetc interfaces.This allows you to cast to/from byte arrays, and to/from other integer or number types.