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

时间:2017-04-05 09:43:41

标签: c# arrays json serialization hash

当我使用binaryformatter来序列化对象时,我遇到了一个小麻烦。序列化的重点是使值可以传递到需要字节数组的散列函数中。

我的过程是,我读取文件,使用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 = "";

    }
}

E.g

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";

在上面的示例中,objectA的字节数组的值是相同的,当在写出数据和读回文件期间生成散列值时。

但是,对于objectB,值不同。

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

    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.kamal\User1.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); 
    }

e.g。

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

1 个答案:

答案 0 :(得分:0)

我建议你以不同的方式比较字节而不是哈希代码方法: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} \n\n", 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} \n\n", 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} \n\n", 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");
        }
    }
}

这是一个有效的Demo

希望这会对你有所帮助