From a374d529dd1f72b7ff5015a2e39607e393428a5a Mon Sep 17 00:00:00 2001 From: Bevan Weiss Date: Sat, 3 Jun 2023 11:38:07 +1000 Subject: [PATCH] As reported in Issue #216, when using a calculated binding, with a ValueGetter, the getter appears to be evaluted only once when initially converted to a TypeNode. This is unfortunately prior to any deserialized values being realised. This is a slightly hacky solution, but simply re-attempts to evaluate getters where this is the case. Signed-off-by: Bevan Weiss --- .../Issues/Issue216/Issue216Test.cs | 27 +++++++++++++++++++ .../Issues/Issue216/PreviewClass.cs | 27 +++++++++++++++++++ BinarySerializer/Graph/Binding.cs | 6 +++++ 3 files changed, 60 insertions(+) create mode 100644 BinarySerializer.Test/Issues/Issue216/Issue216Test.cs create mode 100644 BinarySerializer.Test/Issues/Issue216/PreviewClass.cs diff --git a/BinarySerializer.Test/Issues/Issue216/Issue216Test.cs b/BinarySerializer.Test/Issues/Issue216/Issue216Test.cs new file mode 100644 index 00000000..eae0fee4 --- /dev/null +++ b/BinarySerializer.Test/Issues/Issue216/Issue216Test.cs @@ -0,0 +1,27 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace BinarySerialization.Test.Issues.Issue216 +{ + [TestClass] + public class Issue216Tests : TestBase + { + [TestMethod] + public void TestIssue216() + { + var expected = new Preview + { + ResolutionX = 2, + ResolutionY = 3, + Data = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }, + Empty = 0, + }; + + var actual = Roundtrip(expected, new byte[] { 2, 0, 0, 0, 3, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0, 0 }); + Assert.AreEqual(expected.ResolutionX, actual.ResolutionX); + Assert.AreEqual(expected.ResolutionY, actual.ResolutionY); + Assert.AreEqual(expected.Data.Length, actual.Data.Length); + for (int i = 0; i < expected.Data.Length; i++) + Assert.AreEqual(expected.Data[i], actual.Data[i]); + } + } +} diff --git a/BinarySerializer.Test/Issues/Issue216/PreviewClass.cs b/BinarySerializer.Test/Issues/Issue216/PreviewClass.cs new file mode 100644 index 00000000..1eb8ba00 --- /dev/null +++ b/BinarySerializer.Test/Issues/Issue216/PreviewClass.cs @@ -0,0 +1,27 @@ +namespace BinarySerialization.Test.Issues.Issue216 +{ + public class Preview + { + /// + /// Gets the image width, in pixels. + /// + [FieldOrder(0)] + public uint ResolutionX { get; set; } + + /// + /// Gets the image height, in pixels. + /// + [FieldOrder(2)] + public uint ResolutionY { get; set; } + + [Ignore] + public uint DataSize => ResolutionX * ResolutionY * 2; + + [FieldOrder(3)] + [FieldCount(nameof(DataSize), BindingMode = BindingMode.OneWay)] + public byte[] Data { get; set; } + + [FieldOrder(4)] + public uint Empty; + } +} diff --git a/BinarySerializer/Graph/Binding.cs b/BinarySerializer/Graph/Binding.cs index cad186e7..8c696c98 100644 --- a/BinarySerializer/Graph/Binding.cs +++ b/BinarySerializer/Graph/Binding.cs @@ -77,6 +77,12 @@ public object GetValue(ValueNode target) CheckSource(source); + // When using a calculated Ignore field, the evaluation of the value is not + // deferred until required non-Ignore fields are calculated. + // This is a hack, but if the value is null, we will re-evaluate the getter + if (source.Value == null && source.TypeNode.ValueGetter != null) + source.Value = source.TypeNode.ValueGetter.Invoke(source.Parent.Value); + return ValueConverter == null ? source.Value : Convert(source.Value, target.CreateLazySerializationContext());