Преобразование несериализуемых классов в байтовый массив

У меня есть сценарий, в котором я синхронизирую данные между несколькими ОЧЕНЬ разными системами. (Сами данные похожи, но таблицы в разных системах имеют совершенно разные форматы.) Чтобы облегчить эту синхронизацию, у меня есть таблица базы данных, в которой хранятся хэши объектов из каждой из систем вместе с ключами элементов и другой соответствующей информацией. Когда хеш объекта из одной системы изменяется, я обновляю другой.

Моя таблица базы данных выглядит примерно так.

CREATE TABLE [dbo].[SyncHashes](
    [SyncHashId] [int] IDENTITY(1,1) NOT NULL,
    [ObjectName] [nvarchar](50) NULL,
    [MappingTypeValue] [nvarchar](25) NULL,
    [MappingDirectionValue] [nvarchar](25) NULL,
    [SourceSystem] [nvarchar](50) NULL,
    [SourceKey] [nvarchar](200) NULL,
    [SourceHash] [nvarchar](50) NULL,
    [TargetSystem] [nvarchar](50) NULL,
    [TargetKey] [nvarchar](200) NULL,
    [TargetHash] [nvarchar](50) NULL,
    [UpdateNeededValue] [nvarchar](max) NULL,
    [CreatedOn] [datetime] NULL,
    [ModifiedOn] [datetime] NULL,
    [Version] [timestamp] NOT NULL, 
    [IsActive] [bit] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [SyncHashId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Пока все хорошо. Но...

Чтобы эффективно вычислить хэш (например, MD5-хэш (это то, что я использую)) для объекта, вы должны иметь возможность преобразовать его в массив байтов .

И ...

Кажется, что для преобразования объекта в массив байтов он должен быть сериализуемым . (По крайней мере, это то, что я прочитал, и ошибки, которые я получаю от .NET, похоже, указывают на то, что это правда.)

Для одной из систем у меня есть возможность сделать все объекты моей базы данных сериализуемыми, так что это здорово. . Генерируются хэши, все синхронизируется, и мир прекрасен!

Для другой системы дела не так хороши . Мне передан контекст базы данных из модели платформы 4 (сначала код), и объекты НЕ сериализованы .

Когда я пытаюсь преобразовать в байты, используя что-то вроде следующего, .NET жалуется и устраивает небольшую истерику - все время отказываясь предоставить мне красивый маленький массив байтов, о котором я так вежливо просил.

foreach(var dataItem in context.TableName)
{
    var byteArray = (byte[]) dataItem;
}

Хорошо. Без проблем.

У меня есть небольшой красивый метод расширения, который, как я думал, может помочь.

public static byte[] ObjectToByteArray<T>(this T obj)
{
    if (obj == null)
        return null;
    BinaryFormatter bf = new BinaryFormatter();
    MemoryStream ms = new MemoryStream();

    bf.Serialize(ms, obj);
    return ms.ToArray();
}

О нет! Если объект (сущность) не сериализуем, эта процедура выдает мне еще одно приятное маленькое (и полностью ожидаемое) исключение.

Итак ... я модифицирую подпрограмму и добавляю предложение where к определению метода вот так.

public static byte[] ObjectToByteArray<T>(this T obj) where T : ISerializable
{
    if (obj == null)
        return null;
    BinaryFormatter bf = new BinaryFormatter();
    MemoryStream ms = new MemoryStream();

    bf.Serialize(ms, obj);
    return ms.ToArray();
}

Единственная проблема в том, что теперь я вернулся к исходной точке, где все мои объекты должны быть сериализуемыми, чтобы получить массив байтов.

Хммм. Нехорошо.

Итак, я собрал хитрость, чтобы перебрать все свойства объекта и сгенерировать строковое представление, из которого я мог бы построить массив байтов. Это было УЖАСНО и НЕЭФФЕКТИВНО, но вроде как помогло.

public static string ComputeMD5Hash<T>(this T input)
{
    StringBuilder sb = new StringBuilder();

    Type t = input.GetType();
    PropertyInfo[] properties = t.GetProperties();

    foreach (var property in properties)
    {
        sb.Append(property.Name);
        sb.Append("|");
        object value = property.GetValue(input, null);
        if (value != null)
        {
            sb.Append(value);
        }
        sb.Append("|");
    }

    return MD5HashGenerator.GenerateKey(sb.ToString());
}

Но ...

После всего этого, я все еще хотел бы иметь возможность эффективно и правильно создавать байтовый массив из объекта, класс которого не помечен как сериализуемый . Как лучше всего этого добиться?

Заранее благодарю!

6
задан Anthony Gatlin 27 October 2011 в 22:28
поделиться