.NET: Convert System.Decimal to and from Byte Arrays

Introduction?

At first, glance converting the datatype (System.Decimal) to and from bytes may appear to be a challenge, this is because the BitConverter and Convert classes do not have methods to convert decimals to and from bytes with. The decimal data type has built-in methods for converting, although they are somewhat obscure. Here are two simple functions for converting decimals to a list of bytes, and then back to a decimal (at the end of the article).

Getting the bytes of a System.Decimal

You may have noticed or not, but the Decimal class has a shared method called "GetBits". This method will return an array containing four 32 bit integers, so not quite the bits you would be expecting. So at first, you might be expecting those four integers to be ones or zeroes. This is not the case. The bits of the decimal is actually extrapolated by taking the bytes of those four 32 bit integers (4*32=128). This means that a decimal is a 128 bit (16 bytes) structure.

Creating an instance of the System.Decimal from bytes

So you may have been in a place where you were pulling your hair out trying to figure out how to get an instance of System.Decimal from those bytes. This is because you may be used to creating instances of numeric datatypes using the BitConverter class or the Convert class. The BitConverter & Convert classes do not have any methods built in to support the Decimal datatype. So this may seem like a really confusing problem at first, but the truth is that the Decimal class has a constructor that accepts an array of exactly four 32 bit integers as a parameter.

Summary

So in a nutshell, this means that you can take your binary information using the Decimal.GetBits function, save it to your file, or whatever you need to do. You can later then load those bytes into an array, convert those bytes into integers, put those integers into another array, and finally, pass that array of integers to the decimal's constructor sub.

?Code Examples

Visual Basic



      'Prevent simple errors with options   
      Option Strict On
      Option Explicit On
      Option Infer Off 
      Public Class  Form1 
                 Private Sub  Button1_Click(sender As Object, e As  EventArgs) Handles Button1.Click   
                 'create a decimal for testing       
                 Dim testDecimal As Decimal  = 987.123456D   
                 'Get the bytes of the decimal       
                 Dim decimalBytes As Byte() = BitconverterExt.GetBytes(testDecimal)   
                 'Create a decimal from those bytes       
                 Dim fromBytes As Decimal  = BitconverterExt.ToDecimal(decimalBytes)   
                 'Display the result       
                 MsgBox(fromBytes.ToString)       
                 End Sub  
      End Class
      Public Class  BitconverterExt 
                 Public Shared  Function GetBytes(dec As Decimal) As  Byte()   
                 'Load four 32 bit integers from the Decimal.GetBits function       
                 Dim bits As Int32() = Decimal.GetBits(dec)   
                 'Create a temporary list to hold the bytes       
                 Dim bytes As New  List(Of Byte)   
                 'iterate each 32 bit integer       
                 For Each  i As  Int32 In  bits   
                 'add the bytes of the current 32bit integer       
                 'to the bytes list       
                 bytes.AddRange(BitConverter.GetBytes(i))       
                 Next      
                 'return the bytes list as an array       
                 Return bytes.ToArray   
                 End Function  
                 Public Shared  Function ToDecimal(bytes As Byte()) As  Decimal  
                 'check that it is even possible to convert the array       
                 If bytes.Count <> 16 Then Throw  New Exception("A decimal must be created from exactly 16 bytes")   
                 'make an array to convert back to int32's       
                 Dim bits(3) As Int32   
                 For i As Integer  = 0 To  15 Step  4   
                 'convert every 4 bytes into an int32       
                 bits(i \ 4) = BitConverter.ToInt32(bytes, i)       
                 Next      
                 'Use the decimal's new constructor to       
                 'create an instance of decimal       
                 Return New  Decimal(bits)   
                 End Function  
      End Class

C#


using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
namespace WindowsFormsApplication1 
{ 
 public partial  class Form1 : Form 
 { 
 public Form1() 
 { 
 InitializeComponent(); 
 } 
 private void  Form1_Load(object sender, EventArgs e){} 
 private void  button1_Click(object sender, EventArgs e) 
 { 
 //create a decimal for testing 
 decimal testDecimal = 987.123456m; 
 //Get the bytes of the decimal 
 byte[] decimalBytes = BitconverterExt.GetBytes(testDecimal); 
 //Create a decimal from those bytes 
 decimal fromBytes = BitconverterExt.ToDecimal(decimalBytes);  
 //Display the result 
 MessageBox .Show(fromBytes.ToString()); 
 } 
 } 
 public class  BitconverterExt 
 { 
 public static  byte[] GetBytes(decimal dec) 
 { 
 //Load four 32 bit integers from the Decimal.GetBits function 
 Int32[] bits = decimal.GetBits(dec); 
 //Create a temporary list to hold the bytes 
 List<byte> bytes = new  List<byte>(); 
 //iterate each 32 bit integer 
 foreach (Int32 i in bits) 
 { 
 //add the bytes of the current 32bit integer 
//to the bytes list 
 bytes.AddRange(BitConverter.GetBytes(i)); 
 } 
 //return the bytes list as an array 
 return bytes.ToArray(); 
 } 
 public static  decimal ToDecimal(byte[] bytes) 
 { 
 //check that it is even possible to convert the array 
 if (bytes.Count() != 16) 
 throw new  Exception("A decimal must be created from exactly 16 bytes"); 
 //make an array to convert back to int32's 
 Int32[] bits = new  Int32[4]; 
 for (int i = 0; i <= 15; i += 4) 
 { 
 //convert every 4 bytes into an int32 
 bits[i/4] = BitConverter.ToInt32(bytes, i); 
 } 
 //Use the decimal's new constructor to 
//create an instance of decimal 
 return new  decimal(bits); 
 } 
 } 
}

ReferencesMSDN Library