--- lang: ja-jp breaks: true --- # MessagePack で `DataSet` `DataTable` を シリアライズ/デシリアライズ したい C# 2021-11-13 `DataSet`、`DataTable` 標準のシリアライザを使用する為、シリアライズ後のサイズは大きくなるがとりあえず対応出来た。 ## DataTable ### NativeDataTableFormatter ```csharp= using System; using System.Buffers; using System.Data; using System.IO; namespace MessagePack.Formatters { /// <summary> /// Serialize by .NET native DataTable XML format. /// </summary> public sealed class NativeDataTableFormatter : IMessagePackFormatter<DataTable> { public static readonly NativeDataTableFormatter Instance = new NativeDataTableFormatter(); public void Serialize( ref MessagePackWriter writer, DataTable value, MessagePackSerializerOptions options ) { if (value == null) { writer.WriteNil(); } else { try { using (var stream = new MemoryStream()) { value.WriteXml( stream, XmlWriteMode.WriteSchema ); byte[] date_Data = null; date_Data = stream.ToArray(); stream.Close(); writer.Write(date_Data); } } catch (Exception ex) { throw; } } } public DataTable Deserialize( ref MessagePackReader reader, MessagePackSerializerOptions options ) { if (reader.TryReadNil()) { return default(DataTable); } else { DataTable dateData = new DataTable(); try { byte[] buffer = reader.ReadBytes().Value.ToArray(); using (var stream = new MemoryStream(buffer)) { XmlReadMode xmlReadMode = dateData.ReadXml(stream); stream.Close(); } } catch (Exception ex) { throw; } return dateData; } } } public sealed class NativeDataTableArrayFormatter : IMessagePackFormatter<DataTable[]> { public static readonly NativeDataTableArrayFormatter Instance = new NativeDataTableArrayFormatter(); public void Serialize(ref MessagePackWriter writer, DataTable[] value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); } else { writer.WriteArrayHeader(value.Length); for (int i = 0; i < value.Length; i++) { NativeDataTableFormatter.Instance.Serialize(ref writer, value[i], options); } } } public DataTable[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return null; } var len = reader.ReadArrayHeader(); if (len == 0) { return Array.Empty<DataTable>(); } var array = new DataTable[len]; for (int i = 0; i < array.Length; i++) { DataTable dataTable = NativeDataTableFormatter.Instance.Deserialize(ref reader, options); array[i] = dataTable; } return array; } } } ``` ### NativeDataTableResolver ```csharp= using System; using System.Data; using MessagePack.Formatters; using MessagePack.Internal; namespace MessagePack.Resolvers { public sealed class NativeDataTableResolver : IFormatterResolver { /// <summary> /// The singleton instance that can be used. /// </summary> public static readonly NativeDataTableResolver Instance; /// <summary> /// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured. /// </summary> public static readonly MessagePackSerializerOptions Options; static NativeDataTableResolver() { Instance = new NativeDataTableResolver(); Options = MessagePackSerializerOptions.Standard.WithResolver(Instance); } private NativeDataTableResolver() { } public IMessagePackFormatter<T> GetFormatter<T>() { return FormatterCache<T>.Formatter; } private static class FormatterCache<T> { public static readonly IMessagePackFormatter<T> Formatter; static FormatterCache() { Formatter = (IMessagePackFormatter<T>)NativeDataTableResolverGetFormatterHelper .GetFormatter(typeof(T)); } } } } namespace MessagePack.Internal { internal static class NativeDataTableResolverGetFormatterHelper { internal static object GetFormatter(Type t) { if (t == typeof(DataTable)) { return NativeDataTableFormatter.Instance; } else if (t == typeof(DataTable[])) { return NativeDataTableArrayFormatter.Instance; } return null; } } } ``` ## DataSet ### NativeDataSetFormatter ```csharp= using System; using System.Buffers; using System.Data; using System.IO; namespace MessagePack.Formatters { /// <summary> /// Serialize by .NET native DataSet XML format. /// </summary> public sealed class NativeDataSetFormatter : IMessagePackFormatter<DataSet> { public static readonly NativeDataSetFormatter Instance = new NativeDataSetFormatter(); public void Serialize( ref MessagePackWriter writer, DataSet value, MessagePackSerializerOptions options ) { if (value == null) { writer.WriteNil(); } else { try { using (var stream = new MemoryStream()) { value.WriteXml( stream, XmlWriteMode.WriteSchema ); byte[] date_Data = null; date_Data = stream.ToArray(); stream.Close(); writer.Write(date_Data); } } catch (Exception ex) { throw; } } } public DataSet Deserialize( ref MessagePackReader reader, MessagePackSerializerOptions options ) { if (reader.TryReadNil()) { return default(DataSet); } else { DataSet dateData = new DataSet(); try { byte[] buffer = reader.ReadBytes().Value.ToArray(); using (var stream = new MemoryStream(buffer)) { XmlReadMode xmlReadMode = dateData.ReadXml(stream); stream.Close(); } } catch (Exception ex) { throw; } return dateData; } } } public sealed class NativeDataSetArrayFormatter : IMessagePackFormatter<DataSet[]> { public static readonly NativeDataSetArrayFormatter Instance = new NativeDataSetArrayFormatter(); public void Serialize(ref MessagePackWriter writer, DataSet[] value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); } else { writer.WriteArrayHeader(value.Length); for (int i = 0; i < value.Length; i++) { NativeDataSetFormatter.Instance.Serialize(ref writer, value[i], options); } } } public DataSet[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return null; } var len = reader.ReadArrayHeader(); if (len == 0) { return Array.Empty<DataSet>(); } var array = new DataSet[len]; for (int i = 0; i < array.Length; i++) { DataSet DataSet = NativeDataSetFormatter.Instance.Deserialize(ref reader, options); array[i] = DataSet; } return array; } } } ``` ### NativeDataSetResolver ```csharp= using System; using System.Data; using MessagePack.Formatters; using MessagePack.Internal; namespace MessagePack.Resolvers { public sealed class NativeDataSetResolver : IFormatterResolver { /// <summary> /// The singleton instance that can be used. /// </summary> public static readonly NativeDataSetResolver Instance; /// <summary> /// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured. /// </summary> public static readonly MessagePackSerializerOptions Options; static NativeDataSetResolver() { Instance = new NativeDataSetResolver(); Options = MessagePackSerializerOptions.Standard.WithResolver(Instance); } private NativeDataSetResolver() { } public IMessagePackFormatter<T> GetFormatter<T>() { return FormatterCache<T>.Formatter; } private static class FormatterCache<T> { public static readonly IMessagePackFormatter<T> Formatter; static FormatterCache() { Formatter = (IMessagePackFormatter<T>)NativeDataSetResolverGetFormatterHelper .GetFormatter(typeof(T)); } } } } namespace MessagePack.Internal { internal static class NativeDataSetResolverGetFormatterHelper { internal static object GetFormatter(Type t) { if (t == typeof(DataSet)) { return NativeDataSetFormatter.Instance; } else if (t == typeof(DataSet[])) { return NativeDataSetArrayFormatter.Instance; } return null; } } } ``` ## 型付DataSet ### TypedDataSetFormatter ```csharp= using System; using System.Buffers; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq.Expressions; using System.Reflection; namespace MessagePack.Formatters { /// <summary> /// Serialize by .NET typed DataSet XML format. /// </summary> public sealed class TypedDataSetFormatter<TDataSet> : IMessagePackFormatter<TDataSet> { public static readonly TypedDataSetFormatter<TDataSet> Instance = new TypedDataSetFormatter<TDataSet>(); private static Dictionary<Guid, Func<TDataSet>> ConstructorInfoCache = new (); public void Serialize( ref MessagePackWriter writer, TDataSet value, MessagePackSerializerOptions options ) { if ( value == null || value.GetType().BaseType != typeof(DataSet) ) { writer.WriteNil(); } else { try { using (var stream = new MemoryStream()) { DataSet dataSet = value as DataSet; dataSet.WriteXml( stream, XmlWriteMode.WriteSchema ); byte[] date_Data = null; date_Data = stream.ToArray(); stream.Close(); writer.Write(date_Data); } } catch (Exception ex) { throw; } } } public TDataSet Deserialize( ref MessagePackReader reader, MessagePackSerializerOptions options ) { if (reader.TryReadNil()) { return default(TDataSet); } else { Guid key = typeof(TDataSet).GUID; Func<TDataSet> func = null; lock (ConstructorInfoCache) { if (ConstructorInfoCache.TryGetValue(key, out func) == false) { ConstructorInfo constructorInfo = typeof(TDataSet).GetConstructor(Type.EmptyTypes); ParameterExpression[] parameterExpressions = Array.Empty<ParameterExpression>(); NewExpression instance = Expression.New( constructorInfo, parameterExpressions ); Expression<Func<TDataSet>> lambda = Expression.Lambda<Func<TDataSet>>( instance, parameterExpressions ); func = lambda.Compile(); ConstructorInfoCache.Add(key, func); } } DataSet dateData = func() as DataSet; try { byte[] buffer = reader.ReadBytes().Value.ToArray(); using (var stream = new MemoryStream(buffer)) { XmlReadMode xmlReadMode = dateData.ReadXml(stream); stream.Close(); } } catch (Exception ex) { throw; } return (TDataSet)(object)dateData; } } } public sealed class TypedDataSetArrayFormatter<TDataSet> : IMessagePackFormatter<TDataSet[]> { public static readonly TypedDataSetArrayFormatter<TDataSet> Instance = new TypedDataSetArrayFormatter<TDataSet>(); public void Serialize(ref MessagePackWriter writer, TDataSet[] value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); } else { writer.WriteArrayHeader(value.Length); for (int i = 0; i < value.Length; i++) { TypedDataSetFormatter<TDataSet>.Instance.Serialize(ref writer, value[i], options); } } } public TDataSet[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return null; } var len = reader.ReadArrayHeader(); if (len == 0) { return Array.Empty<TDataSet>(); } var array = new TDataSet[len]; for (int i = 0; i < array.Length; i++) { TDataSet DataSet = TypedDataSetFormatter<TDataSet>.Instance.Deserialize(ref reader, options); array[i] = DataSet; } return array; } } } ``` ### TypedDataSetResolver ```csharp= using System; using System.Data; using MessagePack.Formatters; using MessagePack.Internal; namespace MessagePack.Resolvers { public sealed class TypedDataSetResolver : IFormatterResolver { /// <summary> /// The singleton instance that can be used. /// </summary> public static readonly TypedDataSetResolver Instance; /// <summary> /// A <see cref="MessagePackSerializerOptions"/> instance with this formatter pre-configured. /// </summary> public static readonly MessagePackSerializerOptions Options; static TypedDataSetResolver() { Instance = new TypedDataSetResolver(); Options = MessagePackSerializerOptions.Standard.WithResolver(Instance); } private TypedDataSetResolver() { } public IMessagePackFormatter<T> GetFormatter<T>() { return FormatterCache<T>.Formatter; } private static class FormatterCache<T> { public static readonly IMessagePackFormatter<T> Formatter; static FormatterCache() { Formatter = (IMessagePackFormatter<T>)TypedDataSetResolverGetFormatterHelper .GetFormatter<T>(); } } } } namespace MessagePack.Internal { internal static class TypedDataSetResolverGetFormatterHelper { internal static object GetFormatter<TDataSet>() { Type t = typeof(TDataSet); if (t.BaseType == typeof(DataSet)) { return TypedDataSetFormatter<TDataSet>.Instance; } else if (t.BaseType == typeof(System.Array)) { if (t.GetElementType()?.BaseType == typeof(DataSet)) { return TypedDataSetArrayFormatter<TDataSet>.Instance; } } return null; } } } ``` ## MessagePackSerializerOptions ```csharp= public class MessagePackSerializerOption { public static MessagePackSerializerOptions Option; static MessagePackSerializerOption() { IFormatterResolver customResolver = MessagePack.Resolvers.CompositeResolver.Create( NativeDateTimeResolver.Instance, TypedDataSetResolver.Instance, NativeDataSetResolver.Instance, NativeDataTableResolver.Instance, ContractlessStandardResolverAllowPrivate.Instance ); Option = ContractlessStandardResolverAllowPrivate.Options .WithCompression(MessagePackCompression.Lz4Block) .WithResolver(customResolver) ; } } ``` ###### tags: `MessagePack` `DataSet` `DataTable` `型付DataSet` `シリアライズ` `デシリアライズ` `式木` `キャッシュ` `C#`