簡體   English   中英

如何在C#或Linq中比較大於或小於運算符值的兩個字節數組?

[英]How to compare two byte arrays with greater than or less than operator value in C# or Linq?

我在Code TimeStamps的Code First Entity Framework中有一個字節數組,映射如下:

 [Column(TypeName = "timestamp")]
 [MaxLength(8)]
 [Timestamp]
 public byte[] TimeStamps { get; set; }

上述屬性等於C#中的SQL服務器“timestamp”數據類型。

在SQL服務器中,我可以輕松比較“時間戳”,如下所示......

SELECT * FROM tableName WHERE timestampsColumnName > 0x000000000017C1A2

我希望在C#或Linq Query中實現同樣的功能。 在這里,我編寫了我的Linq查詢,該查詢無法正常工作。

 byte[] lastTimeStamp = someByteArrayValue;
 lstCostCenter.Where(p => p.TimeStamps > lastTimeStamp);

我也嘗試用BitConverter來比較一個雙字節數組,這個數組也無效......

 lstCostCenter.Where(p => BitConverter.ToInt64(p.TimeStamps, 0) > BitConverter.ToInt64(lastTimeStamp, 0));

如何比較C#或Linq Query中的字節數組。

注意 - 我只是不想比較兩個數組,就像使用SequenceEqual或任何其他方法只是比較並返回true或false。 我希望Linq查詢中的比較大於>或小於<運算符,它提供了正確的數據,如SQL Server查詢。

一種方法是使用IStructuralComparableArray隱式實現:

byte[] rv1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01 };
byte[] rv2 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05 };

var result = ((IStructuralComparable)rv1).CompareTo(rv2, Comparer<byte>.Default); // returns negative value, because rv1 < rv2

如果由於某種原因你想使用BitConverter ,你必須反轉數組,因為BitConverter在大多數架構上都是小端(為了安全起見 - 你應該檢查BitConverter.IsLittleEndian字段並且只有在它返回true時才反向)。 請注意,這樣做效率不高。

var i1 = BitConverter.ToUInt64(rv1.Reverse().ToArray(), 0);
var i2 = BitConverter.ToUInt64(rv2.Reverse().ToArray(), 0);

現在,如果您使用Entity Framework並且需要比較數據庫查詢中的時間戳,情況會有所不同,因為Entity Framework將檢查您的查詢表達式,以查找它理解的模式。 它不了解IStructuralComparable比較(當然還有BitConverter轉換),所以你必須使用技巧。 使用名稱Compare聲明字節數組的擴展方法:

static class ArrayExtensions {
    public static int Compare(this byte[] b1, byte[] b2) {
        // you can as well just throw NotImplementedException here, EF will not call this method directly
        if (b1 == null && b2 == null)
            return 0;
        else if (b1 == null)
            return -1;
        else if (b2 == null)
            return 1;
        return ((IStructuralComparable) b1).CompareTo(b2, Comparer<byte>.Default);
    }
}

並在EF LINQ查詢中使用它:

var result = ctx.TestTables.Where(c => c.RowVersion.Compare(rv1) > 0).ToList();

分析時,EF將看到名稱為Compare和兼容簽名的方法,並將其轉換為正確的sql查詢(從表中選擇*,其中RowVersion> @yourVersion)

如果您知道兩個字節數組的長度相等且是最重要的字節,則可以使用:

Func<byte[], byte[], bool> isGreater =
    (xs, ys) =>
        xs
            .Zip(ys, (x, y) => new { x, y })
            .Where(z => z.x != z.y)
            .Take(1)
            .Where(z => z.x > z.y)
            .Any();

如果我測試以下內容:

byte[] rv1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01 };
byte[] rv2 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05 };

Console.WriteLine(isGreater(rv1, rv2));
Console.WriteLine(isGreater(rv2, rv1));

...我得到了預期的結果:

False
True

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM