Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: SerializeAs Support IValueConverter #200

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions BinarySerializer.Test/Issues/issue199/Issue199Tests.cs
Original file line number Diff line number Diff line change
@@ -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<OutputChannelInt>(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;
}

}
}
58 changes: 58 additions & 0 deletions BinarySerializer.Test/Issues/issue199/TestClass.cs
Original file line number Diff line number Diff line change
@@ -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<DistData> 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<DistDataInt> 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)
};
}
}
2 changes: 1 addition & 1 deletion BinarySerializer/Graph/Binding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public object ConstValue
return _constValue;
}
}

public object GetValue(ValueNode target)
{
if (IsConst)
Expand Down
12 changes: 7 additions & 5 deletions BinarySerializer/Graph/TypeGraph/TypeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ protected TypeNode(TypeNode parent, Type parentType, MemberInfo memberInfo, Type
Order = fieldOrderAttribute.Order;
}

var serializeAsAttribute = attributes.OfType<SerializeAsAttribute>().SingleOrDefault();
if (serializeAsAttribute != null)
SerializeAsAttribute = attributes.OfType<SerializeAsAttribute>().SingleOrDefault();
if (SerializeAsAttribute != null)
{
_serializedType = serializeAsAttribute.SerializedType;
_serializedType = SerializeAsAttribute.SerializedType;

#pragma warning disable 618
if (_serializedType == SerializedType.NullTerminatedString)
Expand All @@ -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;
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -345,6 +346,7 @@ protected TypeNode(TypeNode parent, Type parentType, MemberInfo memberInfo, Type
public ReadOnlyCollection<FieldValueAttributeBase> FieldValueAttributes { get; }
public ReadOnlyCollection<SubtypeBaseAttribute> SubtypeAttributes { get; }
public SubtypeDefaultAttribute SubtypeDefaultAttribute { get; }
public SerializeAsAttribute SerializeAsAttribute { get; }
public ISubtypeFactory SubtypeFactory { get; }
public ISubtypeFactory ItemSubtypeFactory { get; }
public ReadOnlyCollection<SubtypeBaseAttribute> ItemSubtypeAttributes { get; }
Expand Down
37 changes: 34 additions & 3 deletions BinarySerializer/Graph/ValueGraph/ValueValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public override object BoundValue
}
}

return ConvertToFieldType(value);
return ConvertToFieldType(value,false);
}
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
19 changes: 16 additions & 3 deletions BinarySerializer/SerializeAsAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using BinarySerialization.Graph;
using System;

namespace BinarySerialization
{
Expand All @@ -11,14 +12,17 @@ public sealed class SerializeAsAttribute : Attribute
/// <summary>
/// Initializes a new instance of the <see cref="SerializeAsAttribute" /> class.
/// </summary>
public SerializeAsAttribute()
public SerializeAsAttribute(Type converterType=null, object converterParameter = null)
{
ConverterType = converterType;
ConverterParameter = converterParameter;
}

/// <summary>
/// Initializes a new instance of the SerializeAs class with a specified <see cref="SerializedType" />.
/// </summary>
public SerializeAsAttribute(SerializedType serializedType)
public SerializeAsAttribute(SerializedType serializedType, Type converterType = null, object converterParameter = null)
: this(converterType, converterParameter)
{
SerializedType = serializedType;
}
Expand All @@ -37,5 +41,14 @@ public SerializeAsAttribute(SerializedType serializedType)
/// Specifies padding value to be used when serializing fixed-size fields.
/// </summary>
public byte PaddingValue { get; set; }
/// <summary>
/// An optional converter to be used converting from the source value to the target binding.
/// </summary>
public Type ConverterType { get; set; }

/// <summary>
/// An optional converter parameter to be passed to the converter.
/// </summary>
public object ConverterParameter { get; set; }
}
}