故事是這樣的,我通常使用 EF 來對 SQL Server 資料庫進行操作,而其中一個資料表欄位的型態是 timestamp,timestamp 是二進位數字(Byte[])的資料類型,在資料庫裡面的資料呈現是這樣子 0x000000000000DDE8,所以當轉成 C# 資料型別的時候會轉型成 byte[]。 而其我遇到一個需求是要找到最大的 byte[] 來做事情。

使用 IStructuralComparable 比較

IStructuralComparable 介面能夠讓你自定義 Collection 的比較,該介面只有提供一個方法 CompareTo,請參考下方比較兩個 byte[] 程式碼範例。

IStructuralComparable
  • cs
1
2
3
4
5
byte[] rv1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01 };
byte[] rv2 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05 };

int result = ((IStructuralComparable)rv1)
.CompareTo(rv2, Comparer<byte>.Default);
  • Comparer<T>.Default 是 .NET Framework 提供的 default comparers ,範例程式碼用 Comparer<byte>.Default 指定 byte 的方式來比較。
  • 當 rv1 小於 rv2 則會回傳負數,反之為正數,相等會為 0。

使用 BitConverter.ToUInt64() 的比較方式

我們也可以用 BitConverter 提供的方法,把 Array 轉成數字來比較。 但是這要注意一件事情,不同的電腦架構,在儲存 byte 資料的順序上會有所不同,讓我們看 msdn 的說明

Different computer architectures store data using different byte orders. “Big-endian” means the most significant byte is on the left end of a word. “Little-endian” means the most significant byte is on the right end of a word.

而 BitConverter.IsLittleEndian 就是能夠讓你判斷電腦是用哪一種方式儲存 byte ,所以當 BitConverter.IsLittleEndian 是 true 的時候,一定要先 Reverse byte[],否則算出來的數字可能會不正確,請參考下方程式碼。

BitConverter
  • cs
1
2
3
var i1 = BitConverter.ToUInt64(rv1.Reverse().ToArray(), 0);
var i2 = BitConverter.ToUInt64(rv2.Reverse().ToArray(), 0)
bool isi1LessThani2 = i1 < i2;

小結

平常很少做到比較 byte[] 的事情,但是當要比較的時候,才知道有這麼多眉角。

延伸閱讀

[Stack overflow - How to compare two byte arrays with greater than or less than operator value in C# or Linq?]
[IStructuralComparable Interface]
[BitConverter.IsLittleEndian Field]
[Comparer.Default Property]