diff --git a/BinarySerializer.Test/Issues/issue199/Issue199Tests.cs b/BinarySerializer.Test/Issues/issue199/Issue199Tests.cs new file mode 100644 index 00000000..5cbc2c76 --- /dev/null +++ b/BinarySerializer.Test/Issues/issue199/Issue199Tests.cs @@ -0,0 +1,41 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; +using System; +using BinarySerialization; +using Test_BinarySerialzer; +using BinarySerialization.Test.Misc; +using System.IO; +using BinarySerialization.Test.Issues.Issue106; + +namespace BinarySerialization.Test.Issues.issue199 +{ + [TestClass] + public class Issue199Tests : TestBase + { + BinarySerializer serializer = new BinarySerializer(); + [TestMethod] + public void Test() + { + var sourcebuffer = StringToByte("A ED7 F13 F25 F26 EBC E82 E60 E43 DD9 DC3 "); + var testType = serializer.Deserialize(sourcebuffer); + Assert.AreEqual(testType.DataAmount, testType.DistDatas.Count); + Assert.AreEqual(Convert.ToInt32("ED7", 16), testType.DistDatas[0].Data); + var stream = new MemoryStream(); + serializer.Serialize(stream, testType); + var serializeBuffer = stream.ToArray(); + CollectionAssert.AreEqual(sourcebuffer, serializeBuffer); + } + + public static byte[] StringToByte(string str) + { + byte[] bytes = new byte[str.Length]; + for (int i = 0; i < str.Length; i++) + { + bytes[i] = (byte)str[i]; + } + + return bytes; + } + + } +} \ No newline at end of file diff --git a/BinarySerializer.Test/Issues/issue199/TestClass.cs b/BinarySerializer.Test/Issues/issue199/TestClass.cs new file mode 100644 index 00000000..7cb2ed3b --- /dev/null +++ b/BinarySerializer.Test/Issues/issue199/TestClass.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using BinarySerialization; + +public class Issue199TestsClass +{ + [FieldOrder(0)] + [SerializeAs(SerializedType.TerminatedString, StringTerminator = (char)0x20)] + public string DataAmount { get; set; } + + //数据列表 + [FieldOrder(1)] + [FieldCount(nameof(DataAmount), ConverterType = typeof(HexStringToIntConvert))] + public List DistDatas { get; set; } + + public class DistData + { + [SerializeAs(SerializedType.TerminatedString, StringTerminator = (char)0x20)] + public string Data { get; set; } + } +} + +public class OutputChannelInt +{ + [FieldOrder(0)] + [SerializeAs(SerializedType.TerminatedString, StringTerminator = (char)0x20, ConverterType = typeof(HexStringToIntConvert))] + public int DataAmount { get; set; } + + //数据列表 + [FieldOrder(1)] + [FieldCount(nameof(DataAmount))] + public List DistDatas { get; set; } + + public class DistDataInt + { + [SerializeAs(SerializedType.TerminatedString, StringTerminator = (char)0x20, ConverterType = typeof(HexStringToIntConvert))] + public int Data { get; set; } + } +} + +class HexStringToIntConvert : IValueConverter +{ + // Read + public object Convert(object value, object parameter, BinarySerializationContext context) + { + return (System.Convert.ToInt32((string)value, 16)); + } + + //Write + public object ConvertBack(object value, object parameter, BinarySerializationContext context) + { + return value switch + { + int intValue => intValue.ToString("X"), + long longValue => longValue.ToString("X"), + _ => (value) + }; + } +} \ No newline at end of file diff --git a/BinarySerializer/Graph/Binding.cs b/BinarySerializer/Graph/Binding.cs index cad186e7..7475e844 100644 --- a/BinarySerializer/Graph/Binding.cs +++ b/BinarySerializer/Graph/Binding.cs @@ -60,7 +60,7 @@ public object ConstValue return _constValue; } } - + public object GetValue(ValueNode target) { if (IsConst) diff --git a/BinarySerializer/Graph/TypeGraph/TypeNode.cs b/BinarySerializer/Graph/TypeGraph/TypeNode.cs index ccb5ab65..2c07e049 100644 --- a/BinarySerializer/Graph/TypeGraph/TypeNode.cs +++ b/BinarySerializer/Graph/TypeGraph/TypeNode.cs @@ -142,10 +142,10 @@ protected TypeNode(TypeNode parent, Type parentType, MemberInfo memberInfo, Type Order = fieldOrderAttribute.Order; } - var serializeAsAttribute = attributes.OfType().SingleOrDefault(); - if (serializeAsAttribute != null) + SerializeAsAttribute = attributes.OfType().SingleOrDefault(); + if (SerializeAsAttribute != null) { - _serializedType = serializeAsAttribute.SerializedType; + _serializedType = SerializeAsAttribute.SerializedType; #pragma warning disable 618 if (_serializedType == SerializedType.NullTerminatedString) @@ -157,10 +157,10 @@ protected TypeNode(TypeNode parent, Type parentType, MemberInfo memberInfo, Type if (_serializedType.Value == SerializedType.TerminatedString) { AreStringsTerminated = true; - StringTerminator = serializeAsAttribute.StringTerminator; + StringTerminator = SerializeAsAttribute.StringTerminator; } - PaddingValue = serializeAsAttribute.PaddingValue; + PaddingValue = SerializeAsAttribute.PaddingValue; } IsNullable = NullableUnderlyingType != null; @@ -312,6 +312,7 @@ protected TypeNode(TypeNode parent, Type parentType, MemberInfo memberInfo, Type } + public MemberInfo MemberInfo { get; } public Type Type { get; } public Type NullableUnderlyingType { get; } @@ -345,6 +346,7 @@ protected TypeNode(TypeNode parent, Type parentType, MemberInfo memberInfo, Type public ReadOnlyCollection FieldValueAttributes { get; } public ReadOnlyCollection SubtypeAttributes { get; } public SubtypeDefaultAttribute SubtypeDefaultAttribute { get; } + public SerializeAsAttribute SerializeAsAttribute { get; } public ISubtypeFactory SubtypeFactory { get; } public ISubtypeFactory ItemSubtypeFactory { get; } public ReadOnlyCollection ItemSubtypeAttributes { get; } diff --git a/BinarySerializer/Graph/ValueGraph/ValueValueNode.cs b/BinarySerializer/Graph/ValueGraph/ValueValueNode.cs index edd1607b..80cca475 100644 --- a/BinarySerializer/Graph/ValueGraph/ValueValueNode.cs +++ b/BinarySerializer/Graph/ValueGraph/ValueValueNode.cs @@ -89,7 +89,7 @@ public override object BoundValue } } - return ConvertToFieldType(value); + return ConvertToFieldType(value,false); } } @@ -489,7 +489,7 @@ public void Deserialize(BinaryReader reader, SerializedType serializedType, Fiel throw new NotSupportedException(TypeNotSupportedMessage); } - _value = ConvertToFieldType(value); + _value = ConvertToFieldType(value,true); // check computed values (CRCs, etc.) CheckComputedValues(); @@ -565,7 +565,7 @@ public async Task DeserializeAsync(AsyncBinaryReader reader, SerializedType seri throw new NotSupportedException(TypeNotSupportedMessage); } - _value = ConvertToFieldType(value); + _value = ConvertToFieldType(value,true); // check computed values (CRCs, etc.) CheckComputedValues(); @@ -834,6 +834,37 @@ private object GetValue(object value, SerializedType serializedType) return value; } + private object ConvertToFieldType(object value,bool isDeserialize) + { + if (TypeNode.SerializeAsAttribute?.ConverterType!=null) + { + if (value == null) + { + return null; + } + var valueConverter = Activator.CreateInstance(TypeNode.SerializeAsAttribute.ConverterType) as IValueConverter; + + if (valueConverter == null) + { + var message = $"{TypeNode.SerializeAsAttribute.ConverterType} does not implement IValueConverter."; + throw new InvalidOperationException(message); + } + + var converterParameter = TypeNode.SerializeAsAttribute.ConverterParameter; + + if (isDeserialize) + { + return valueConverter.Convert(value, converterParameter, CreateLazySerializationContext()); + } + else + { + return valueConverter.ConvertBack(value, converterParameter, CreateLazySerializationContext()); + } + + } + + return ConvertToFieldType(value); + } private object ConvertToFieldType(object value) { return value.ConvertTo(TypeNode.Type); diff --git a/BinarySerializer/SerializeAsAttribute.cs b/BinarySerializer/SerializeAsAttribute.cs index d760c267..965e7967 100644 --- a/BinarySerializer/SerializeAsAttribute.cs +++ b/BinarySerializer/SerializeAsAttribute.cs @@ -1,4 +1,5 @@ -using System; +using BinarySerialization.Graph; +using System; namespace BinarySerialization { @@ -11,14 +12,17 @@ public sealed class SerializeAsAttribute : Attribute /// /// Initializes a new instance of the class. /// - public SerializeAsAttribute() + public SerializeAsAttribute(Type converterType=null, object converterParameter = null) { + ConverterType = converterType; + ConverterParameter = converterParameter; } /// /// Initializes a new instance of the SerializeAs class with a specified . /// - public SerializeAsAttribute(SerializedType serializedType) + public SerializeAsAttribute(SerializedType serializedType, Type converterType = null, object converterParameter = null) + : this(converterType, converterParameter) { SerializedType = serializedType; } @@ -37,5 +41,14 @@ public SerializeAsAttribute(SerializedType serializedType) /// Specifies padding value to be used when serializing fixed-size fields. /// public byte PaddingValue { get; set; } + /// + /// An optional converter to be used converting from the source value to the target binding. + /// + public Type ConverterType { get; set; } + + /// + /// An optional converter parameter to be passed to the converter. + /// + public object ConverterParameter { get; set; } } } \ No newline at end of file