How to Convert from byte? to byte[]? - c#

I am trying to convert a byte received from a database query.
EF Core returns nullable tinyint as byte? and I need to convert it to decimal.
Is there any way to convert it OnModelCreating with model builder in the DbContext?
I am not very familiar with EF Core. So far I only managed to do this - after I already got my object in handler:
decimal? newDecimal = Convert.ToDecimal(BitConverter.ToDouble(AddByteToArray(priceByte), 0)));
private static byte[] AddByteToArray(byte? newByte)
{
if (newByte != null)
{
if(newByte == 0)
{
return Enumerable.Repeat((byte)0x0, 8).ToArray();
}
byte[] bArray = new byte[1];
// Not sure how to convert a non null and byte > 0 to byte[]?? As double requires byte[] while the tinyint return byte from the database
return bArray;
}
return null;
}

I think you are getting a little confused by the types here. The DB returns a byte? for a tinyint because a tinyint has only 8 bits of data. But otherwise it is an integer. If you want to convert it to a decimal, you would use the same mechanism as you would to convert an int or a long to a decimal: cast it. You do not want to convert a byte array to a decimal as that will try to interpret the data in the array as a binary representation of a decimal (see my last paragraph). So this code should suffice to do the conversion.
decimal? d = newByte == null ? null : (decimal)newByte;
See that such a conversion is possible here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions
Note the remarks section here that indicates we are dealing with a binary representation of the number, where care must be taken in dealing with endianness, etc.
https://learn.microsoft.com/en-us/dotnet/api/system.bitconverter?view=net-6.0#remarks
Basically, numbers larger than a byte are technically stored as an array of bytes (since all memory is byte addressable in x86) but the interpration of those bytes into a number depends on the type of the number. For floating point numbers especially the structure of data inside the byte array is complex, broken into fields that represent the base, exponent and sign. And those are not always interpreted in a straightforward way. If you just give a byte array with 27 as the first byte, you don't know where that ends up in the several fields that make up the binary representation of a double. It may well work, but probably not.

Instead of
byte[] bArray = new byte[1];
You can use
byte[] bArray = {(byte)newByte};

Related

A letter in a byte? C#

I have an imported C++ method that receives a byte parameter, but according to the documentation, I can send a letter to that parameter, this is the C++ and C# method:
int WINAPI Sys_InitType(HID_DEVICE device, BYTE type)
public static extern int Sys_InitType(IntPtr device, byte type);
This causes me a syntax error in C#, how do I send a letter in that parameter?
My code (A bit random):
//CRASHES
byte random = Convert.ToByte("A");
_ = RFIDReader.Sys_SetAntenna(g_hDevice, 0);
int lol = RFIDReader.Sys_InitType(g_hDevice, random);
_ = RFIDReader.Sys_SetAntenna(g_hDevice, 1);
CError.Text = lol.ToString();
Convert.ToByte(string); doesn't do what you think it does, according to the documentation
Converts the specified string representation of a number to an equivalent 8-bit unsigned integer.
This would work byte random = Conver.ToByte("52"); which will return the byte 52.
See here:
https://learn.microsoft.com/en-us/dotnet/api/system.convert.tobyte?view=net-6.0#system-convert-tobyte(system-string)
As was pointed out in the comment already, you will have to use character instead of string, so either this
byte random = Convert.ToByte('A');
or a simple cast to byte
byte random = (byte)'A'
In case it is unknown to you, which I didn't assume, a byte can only contain values of the range 0 - 255, while a character can contain everything within the specs of UTF-16.
So this will not work
byte random = Convert.ToByte('\u4542');
And result in the error:
Value was either too large or too small for an unsigned byte.
https://dotnetfiddle.net/anjxt5

In C#, is it possible to cast a byte array into another type without creating a new array?

I have a byte[] object that I'm using as a data buffer.
I want to "read" it as an array of a either primitive/non-primitive structs without duplicating the byte[] data in memory.
The goal would be something like:
byte[] myBuffer;
//Buffer is populated
int[] asInts = PixieDust_ToInt(myBuffer);
MyStruct[] asMyStructs = PixieDust_ToMyStruct(myBuffer);
Is this possible? If so, how?
Is it possible? Practically, yes!
Since .NET Core 2.1, MemoryMarshal lets us do this for spans. If you are satisfied with a span instead of an array, then yes.
var intSpan = MemoryMarshal.Cast<byte, int>(myByteArray.AsSpan());
The int span will contain byteCount / 4 integers.
As for custom structs... The documentation claims to require a "primitive type" on both sides of the conversion. However, you might try using a ref struct and see that is the actual constraint. I wouldn't be surprised if it worked!
Note that ref structs are still very limiting, but the limitation makes sense for the kind of reinterpret casts that we are talking about.
Edit: Wow, the constraint is much less strict. It requires any struct, rather than a primitive. It does not even have to be a ref struct. There is only a runtime check that will throw if your struct contains a reference type anywhere in its hierarchy. That makes sense. So this should work for your custom structs as well as it does for ints. Enjoy!
You will not be able to do this. To have a MyStruct[] you'll need to actually create such an array of that type and copy the data over. You could, in theory, create your own custom type that acted as a collection, but was actually just a facade over the byte[], copying the bytes out into the struct objects as a given value was accessed, but if you end up actually accessing all of the values, this would end up copying all of the same data eventually, it would just potentially allow you to defer it a bit and may be helpful if you only actually use a small number of the values.
Consider class System.BitConverter
This class has functions to reinterpret the bytes starting at a given index as an Int32, Int64, Double, Boolean, etc. and back from those types into a sequence of bytes.
Example:
int32 x = 0x12345678;
var xBytes = BitConverter.GetBytes(x);
// bytes is a byte array with length 4: 0x78; 0x56; 0x34; 0x12
var backToInt32 = BitConverter.ToInt32(xBytes, 0);
Or if your array contains mixed data:
double d = 3.1415;
int16 n = 42;
Bool b = true;
Uint64 u = 0xFEDCBA9876543210;
// to array of bytes:
var dBytes = BitConverter.GetBytes(d);
var nBytes = BitConverter.GetBytes(n);
var bBytes = BitConverter.GetBytes(b);
var uBytes = BitConterter.GetBytes(u);
Byte[] myBytes = dBytes.Concat(nBytes).Concat(bBytes).Concat(uBytes).ToArray();
// startIndexes in myBytes:
int startIndexD = 0;
int startIndexN = dBytes.Count();
int startIndexB = startIndexN + nBytes.Count();
int startIndexU = startIndexB + bBytes.Count();
// back to original elements
double dRestored = Bitconverter.ToDouble(myBytes, startIndexD);
int16 nRestored = BitConverter.ToInt16(myBytes, startIndexN);
bool bRestored = BitConverter.ToBool(myBytes, startIndexB);
Uint64 uRestored = BitConverter.ToUint64(myBytes, startIndexU);
The closest you will get in order to convert a byte[] to other base-types is
Byte[] b = GetByteArray();
using(BinaryReader r = new BinaryReader(new MemoryStream(b)))
{
r.ReadInt32();
r.ReadDouble();
r.Read...();
}
There is however no simple way to convert a byte[] to any kind of object[]

C# Convert Hex string to byte

Little bit stuck on this, I have a var called PORTBhex holding a value in the range 0x00 to 0x3F which is written to an external device via USB. The problem I am having is getting the value into this bit of code:
public bool PORTBwrite()
{
Byte[] outputBuffer = new Byte[65];
outputBuffer[0] = 0;
outputBuffer[1] = 0x00; //Command tells PIC18F4550 we want to write a byte
outputBuffer[0] = 0;
//Must be set to 0
outputBuffer[2] = IO.PORTBhex;
//Hex value 0x00 - 0x3F to write to PORTB
//above line gives the error cannot implicity convert string - byte
//IO.PORTBhex is returned from the code in second snippet
if (writeRawReportToDevice(outputBuffer))
{
return true; //command completed OK
}else{
return false; //command failed .... error stuff goes here
}
}
Now the problem is the value i have is an integer that is converted to hex using:
public static string ToHex(this int value)
{
return string.Format("0x{0:X}", value);
}
The value starts off as an integer and is converted to hex however I cannot use the converted value as its of the wrong type I am getting Cannot implicitly convert type 'string' to 'byte'.
Any idea what I can do to get around this please?
Thanks
EDIT:
I think I might have poorly described what I'm trying to achieve, I have an int variable holding a value in the range 0-255 which I have to convert to Hex which must be formatted to be in the range 0x00 to 0xFF and then set outputBuffer[2] to that value to send to the microcontroller.
The integer var has some maths performed on it before it needs to be converted so i cannot solely use byte vars and has to be converted to a hex byte afterwards.
Thanks
To solution is to change PORTBhex to be of type byte and don't use that ToHex method at all:
Instead of IO.PORTBhex = ToHex(yourIntValue) use this:
IO.PORTBhex = checked((byte)yourIntValue);
It would be even better if you could make yourIntValue to be of type byte, too.
outputBuffer[2] = Convert.ToByte(IO.PORTBhex, 16);
Although personally I'd probably try to avoid strings here in the first place, and just store the byte

Convert GUID to string in decimal base (aka to a huge, comma delimited integer, in base ten)

How can I convert a System.GUID (in C#) to a string in decimal base (aka to a huge, comma delimited integer, in base ten)?
Something like 433,352,133,455,122,445,557,129,...
Guid.ToString converts GUIDs to hexadecimal representations.
I'm using C# and .Net 2.0.
Please be aware that guid.ToByteAray() will NOT return an array that can be passed to BigInteger's constructor. To use the array a re-order is needed and a trailing zero to ensure that Biginteger sees the byteArray as a positive number (see MSDN docs). A simple but less performing function is:
private static string GuidToStringUsingStringAndParse(Guid value)
{
var guidBytes = string.Format("0{0:N}", value);
var bigInteger = BigInteger.Parse(guidBytes, NumberStyles.HexNumber);
return bigInteger.ToString("N0", CultureInfo.InvariantCulture);
}
As Victor Derks pointed out in his answer, you should append a 00 byte to the end of the array to ensure the resulting BigInteger is positive.
According to the the BigInteger Structure (System.Numerics) MSDN Documentation:
To prevent the BigInteger(Byte[]) constructor from confusing the two's complement representation of a negative value with the sign and magnitude representation of a positive value, positive values in which the most significant bit of the last byte in the byte array would ordinarily be set should include an additional byte whose value is 0.
(see also: byte[] to unsigned BigInteger?)
Here's code to do it:
var guid = Guid.NewGuid();
return String.Format("{0:N0}",
new BigInteger(guid.ToByteArray().Concat(new byte[] { 0 }).ToArray()));
using System;
using System.Numerics;
Guid guid = Guid.NewGuid();
byte[] guidAsBytes = guid.ToByteArray();
BigInteger guidAsInt = new BigInteger(guidAsBytes);
string guidAsString = guidAsInt.ToString("N0");
Note that the byte order in the byte array reflects endian-ness of the GUID sub-components.
In the interest of brevity, you can accomplish the same work with one line of code:
string GuidToInteger = (new BigInteger(Guid.NewGuid().ToByteArray())).ToString("N0");
Keep in mind that .ToString("N0") is not "NO"... see the difference?
Enjoy

Byte to integer in C#

I am reading a row from a SQL Server table. One of the columns is of type tinyint.
I want to get the value into an int or int32 variable.
rdr.GetByte(j)
(byte) rdr.GetValue(j)
...seems to be the only way to retrieve the value. But how do I get the result into an int variable?
int value = rdr.GetByte(j);
An explicit cast is not required, because a byte to int is a widening conversion (no possibility of data loss).
See the documentation for BitConverter.ToInt32 (contains more examples):
byte[] bytes = { 0, 0, 0, 25 };
// If the system architecture is little-endian (that is, little end first),
// reverse the byte array.
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
int i = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("int: {0}", i);
// Output: int: 25
Assigning a byte to an int works:
int myInt = myByte;
But maybe you're getting an exception inside IDataRecord.GetByte, in which case you should check that the index you're using to access the data record really points to a tinyint column. You can check the type returned from GetValue. It should be a byte for a tinyint column.
Trace.Assert(rdr.GetValue(j).GetType() == typeof(byte));
Another option is to forego the fragile numeric index altogether:
int myInt = rdr.GetByte(rdr.GetOrdinal(TheNameOfTheTinyintColumn))
(int)rdr.GetByte(j)
Casting the byte to int should work just fine:
int myInt = (int) rdr.GetByte(j);
Since C# supports implicit conversions from byte to int, you can alternatively just do this:
int myInt = rdr.GetByte(j);
Which one you choose is a matter of preference (whether you want to document the fact that a cast is taking place or not). Note that you will need the explicit cast if you want to use type inference, or otherwise myInt will have the wrong type:
var myInt = (int) rdr.GetByte(j);
Quick tidbit I ran into as a kind of corner case. If you have an object type that is of type System.Byte, you can not directly cast to int. You must first cast to a byte, then cast to an int.
public int Method(object myByte)
{
// will throw a cast exception
// var val = (int)myInt;
// will not throw a cast exception
var val = (int)((byte)myInt)
return val;
}
Method((byte)1);
This is similar to Stephen Cleary's comment on the accepted answer, however I am required to specify the size of the int. This worked for me:
int value = Convert.ToInt32(rdr.GetValue(j));
(And it also provided backward compatibility with a database column using an int.)

Categories

Resources