C# 二进制格式化程序属性具有相同的值



当我使用二进制格式化程序序列化对象时,我遇到了一个小障碍。序列化的全部意义在于,可以将值传递到需要字节数组的哈希函数中。

我的过程是,我读取文件,使用newtonsoft Json将json文件转换为POCO对象,进行一些检查,根据需要更新值并以Json格式保存回同一文件。

检查包括验证哈希值是否与文件与进程开始时重新生成的内容匹配。我采取的步骤是,读取文件,转换为 POCO,使用二进制格式化程序序列化,生成哈希值,比较两个值,如果正确,更新数据并将新的哈希值和对象作为 Json 保存到文件中。

但是,当我使用二进制格式化程序序列化对象时,我遇到了一个障碍。如果对象具有值相同的属性,则序列化程序的字节输出不同于从文件读入数据时到写出数据时。由于字节数组的值不同,哈希值也不同。此外,如果属性的值不同,则会生成相同的哈希值,因此没有问题。

我的问题是,为什么在读取对象并将其写入文件时,具有相同的值会导致字节值不同。

[Serializable]
public class UserAuthorisationData
{
public string surname { get; set; }
public string forename { get; set; }
public string initials { get; set; }  
public UserAuthorisationData()
{
surname = "";
forename = "";
initials = "";
}
}

例如

var objectA = new UserAuthorisationData()
objectA.surname = "Fred";
objectA.forename = "John";
objectA.initials = "FJ"; 
var objectB = new UserAuthorisationData()
objectB.surname = "John";
objectB.forename = "John";
objectB.initials = "JJ";

在上面的示例中,当在写出数据和读回文件期间生成哈希值时,对象 A 的字节数组的值是相同的。

但是,对于对象 B,值会有所不同。

下面将对象转换为字节的方法:

protected virtual byte[] ObjectToByteArray(object objectToSerialize)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream fs = new MemoryStream();
try
{
lock (locker)
{                   
formatter.Serialize(fs, objectToSerialize);
Logger.Debug($"Successfully converted object to bytes for serialization.");
}
File.WriteAllBytes(@"C:ali.kamalUser1.txt", fs.ToArray());
return fs.ToArray();
}
}

在对象上调用方法

ObjectToByteArray(objectA);
ObjectToByteArray(objectB);

更新 1

谢谢哈迪。哈希代码是使用 Microsoft 的 HMACSHA256.computeHash 方法生成的。

protected override string ComputeHash(byte[] objectAsBytes, byte[] key)
{
byte[] hashValue = null;
try
{
using (HMACSHA256 hmac = new HMACSHA256(key))
{
hashValue = hmac.ComputeHash(objectAsBytes);
}
}catch(Exception ex)
{
EventLogger.LogEvent($"Could not generate SHA256 hash value, exception:{ex.Message}", EventEntryType.Error);
}
return Convert.ToBase64String(hashValue); 
}

例如

string hashvalue = ComputeHash(ObjectToByteArray(objectA), ObjectToByteArray("abcd"))

我建议您以不同的方式比较字节而不是哈希代码方法:Array1.SequenceEqual(Array2),不清楚您如何在您的问题中比较两个数组的哈希代码,但我会假设您使用的是 GetHashCode 方法,除非您覆盖 HasCode 函数,否则使用Array1.GetHashCode() == Array2.GetHashCode()不适合您的情况。下面是使用控制台应用程序使用SequenceEqual方法的示例:

using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var a = new UserData();
var b = new UserData();
var aS = ObjectToByte(a);
var bS = ObjectToByte(b);
Console.WriteLine("A : {0}", a);
Console.WriteLine("B : {0}", b);
// result for empty objects are equal
Console.WriteLine("A == B ? => {0} nn", aS.SequenceEqual(bS));
a = new UserData()
{
ForeName = "A",
Initials = "CC",
SurName = "B",
};
b = new UserData()
{
ForeName = "AX",
Initials = "CC",
SurName = "B",
};
aS = ObjectToByte(a);
bS = ObjectToByte(b);
Console.WriteLine("A : {0}", a);
Console.WriteLine("B : {0}", b);
// result for same data type with same object values are equal
Console.WriteLine("A == B ? => {0} nn", aS.SequenceEqual(bS));
a = new UserData()
{
ForeName = "AX",
Initials = "CC",
SurName = "B",
};
b = a;
aS = ObjectToByte(a);
bS = ObjectToByte(b);
Console.WriteLine("A : {0}", a);
Console.WriteLine("B : {0}", b);
// result for different objects are not equal
Console.WriteLine("A == B ? => {0} nn", aS.SequenceEqual(bS));
}
static byte[] ObjectToByte(object item)
{
var formatter = new BinaryFormatter();
using (var memory = new MemoryStream())
{
formatter.Serialize(memory, item);
return memory.ToArray();
}
}
}
[Serializable]
public class UserData
{
public string SurName { get; set; }
public string ForeName { get; set; }
public string Initials { get; set; }
public override string ToString()
{
return string.Format("{{SurName: {0} , ForeName:{1}, Initials:{2}}}", SurName ?? "Empty", ForeName ?? "Empty", Initials ?? "Empty");
}
}
}

这是一个工作演示

希望这对你有帮助

最新更新