From d247bf0797927888ebe9700bf44fdec37a127859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 17 Dec 2019 18:39:49 +0100 Subject: [PATCH 1/3] Fix TextCaster to correctly format a DateTime or a Numeric --- NBi.Core/Scalar/Casting/TextCaster.cs | 10 +++++ .../Resolver/FormatScalarResolverTest.cs | 2 + .../Variable/InstanceFactoryTest.cs | 1 + .../Positive/ResultSetConstraint.nbits | 43 +++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/NBi.Core/Scalar/Casting/TextCaster.cs b/NBi.Core/Scalar/Casting/TextCaster.cs index d4b644e9e..58f9b1909 100644 --- a/NBi.Core/Scalar/Casting/TextCaster.cs +++ b/NBi.Core/Scalar/Casting/TextCaster.cs @@ -12,6 +12,16 @@ public string Execute(object value) { if (value is string) return (string)value; + + if (value is DateTime) + return ((DateTime)value).ToString("yyyy-MM-dd hh:mm:ss"); + + if (value is bool) + return (bool)value ? "True" : "False"; + + var numericCaster = new NumericCaster(); + if (numericCaster.IsStrictlyValid(value)) + return Convert.ToDouble(value).ToString(new CultureFactory().Invariant.NumberFormat); return value.ToString(); } diff --git a/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs b/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs index 427288e78..43e466077 100644 --- a/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs +++ b/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs @@ -26,6 +26,7 @@ public void Execute_ExistingNumericVariable_CorrectEvaluation() } [Test] + [Culture("en-us")] public void Execute_VariableWithNativeTransformation_CorrectEvaluation() { var globalVariables = new Dictionary() @@ -40,6 +41,7 @@ public void Execute_VariableWithNativeTransformation_CorrectEvaluation() } [Test] + [Culture("en-us")] public void Execute_VariableWithTwoNativeTransformations_CorrectEvaluation() { var globalVariables = new Dictionary() diff --git a/NBi.Testing.Core/Variable/InstanceFactoryTest.cs b/NBi.Testing.Core/Variable/InstanceFactoryTest.cs index 119995a9f..6f188049e 100644 --- a/NBi.Testing.Core/Variable/InstanceFactoryTest.cs +++ b/NBi.Testing.Core/Variable/InstanceFactoryTest.cs @@ -16,6 +16,7 @@ namespace NBi.Testing.Core.Variable public class InstanceFactoryTest { [Test] + [Culture("en-us")] public void Instantiate_DerivedFromMain_Success() { var resolver = new Mock(); diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index 432616803..3ba6de24c 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -1981,6 +1981,49 @@ + + + + + 39.500 + 8.200 + + + + + + + + 2018-10-01 + 8.200 + + + + 0 + + + + + + 2018-10-01 + 39.500 + + + + + + + + + + + + + + + + + From f388cfadef6a8a4922165c785cfbead9c96fc5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 17 Dec 2019 21:07:47 +0100 Subject: [PATCH 2/3] Fix TextCaster --- NBi.Core/Scalar/Casting/TextCaster.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NBi.Core/Scalar/Casting/TextCaster.cs b/NBi.Core/Scalar/Casting/TextCaster.cs index 58f9b1909..0bcc49506 100644 --- a/NBi.Core/Scalar/Casting/TextCaster.cs +++ b/NBi.Core/Scalar/Casting/TextCaster.cs @@ -14,14 +14,14 @@ public string Execute(object value) return (string)value; if (value is DateTime) - return ((DateTime)value).ToString("yyyy-MM-dd hh:mm:ss"); + return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss"); if (value is bool) return (bool)value ? "True" : "False"; var numericCaster = new NumericCaster(); if (numericCaster.IsStrictlyValid(value)) - return Convert.ToDouble(value).ToString(new CultureFactory().Invariant.NumberFormat); + return Convert.ToDecimal(value).ToString(new CultureFactory().Invariant.NumberFormat); return value.ToString(); } From 5e597a39ffa708e307190893c90a19df7df1134a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 17 Dec 2019 21:57:08 +0100 Subject: [PATCH 3/3] Add an untyped type and the cells' values should always be an object and not a string --- NBi.Core/NBi.Core.csproj | 1 + .../Alteration/Lookup/LookupReplaceEngine.cs | 2 +- NBi.Core/ResultSet/ColumnType.cs | 1 + NBi.Core/ResultSet/ICell.cs | 2 +- .../ResultSet/Resolver/ObjectsToRowsHelper.cs | 4 +- NBi.Core/Scalar/Casting/CasterFactory.cs | 1 + NBi.Core/Scalar/Casting/UntypedCaster.cs | 18 +++++++++ .../Calculation/Ranking/BottomRankingTest.cs | 16 ++++---- .../Calculation/Ranking/TopRankingTest.cs | 17 +++++---- .../Lookup/LookupReplaceEngineTest.cs | 37 +++++++++++++++++++ NBi.Testing.Core/ResultSet/ResultSetTest.cs | 16 ++++---- NBi.Xml/Items/ResultSet/CellXml.cs | 10 ++--- 12 files changed, 93 insertions(+), 32 deletions(-) create mode 100644 NBi.Core/Scalar/Casting/UntypedCaster.cs diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 1ef09debb..7ebe4992b 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -552,6 +552,7 @@ + diff --git a/NBi.Core/ResultSet/Alteration/Lookup/LookupReplaceEngine.cs b/NBi.Core/ResultSet/Alteration/Lookup/LookupReplaceEngine.cs index 1720899a5..a934d112c 100644 --- a/NBi.Core/ResultSet/Alteration/Lookup/LookupReplaceEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Lookup/LookupReplaceEngine.cs @@ -25,7 +25,7 @@ public ResultSet Execute(ResultSet candidate) var stopWatch = new Stopwatch(); stopWatch.Start(); var referenceKeyRetriever = BuildColumnsRetriever(Args.Mapping, x => x.ReferenceColumn); - var referenceValueRetriever = BuildColumnsRetriever(new ColumnMapping(Args.Replacement, ColumnType.Text), x => x.ReferenceColumn); + var referenceValueRetriever = BuildColumnsRetriever(new ColumnMapping(Args.Replacement, ColumnType.Untyped), x => x.ReferenceColumn); var index = BuildReferenceIndex(reference.Table, referenceKeyRetriever, referenceValueRetriever); Trace.WriteLineIf(Extensibility.NBiTraceSwitch.TraceInfo, $"Built the index for reference table containing {index.Count()} rows [{stopWatch.Elapsed:d'.'hh':'mm':'ss'.'fff'ms'}]"); diff --git a/NBi.Core/ResultSet/ColumnType.cs b/NBi.Core/ResultSet/ColumnType.cs index e6092b772..678b00b23 100644 --- a/NBi.Core/ResultSet/ColumnType.cs +++ b/NBi.Core/ResultSet/ColumnType.cs @@ -4,6 +4,7 @@ namespace NBi.Core.ResultSet { public enum ColumnType { + Untyped = -1, [XmlEnum(Name = "text")] Text = 0, [XmlEnum(Name = "numeric")] diff --git a/NBi.Core/ResultSet/ICell.cs b/NBi.Core/ResultSet/ICell.cs index 33db7f7c7..adbd7873c 100644 --- a/NBi.Core/ResultSet/ICell.cs +++ b/NBi.Core/ResultSet/ICell.cs @@ -7,7 +7,7 @@ namespace NBi.Core.ResultSet { public interface ICell { - string Value { get; set; } + object Value { get; set; } string ColumnName { get; set; } } } diff --git a/NBi.Core/ResultSet/Resolver/ObjectsToRowsHelper.cs b/NBi.Core/ResultSet/Resolver/ObjectsToRowsHelper.cs index 53add00ec..208efc223 100644 --- a/NBi.Core/ResultSet/Resolver/ObjectsToRowsHelper.cs +++ b/NBi.Core/ResultSet/Resolver/ObjectsToRowsHelper.cs @@ -17,7 +17,7 @@ public IEnumerable Execute(IEnumerable objects) if (obj is IEnumerable items) foreach (var item in items) { - var cell = new Cell() { Value = item?.ToString() }; + var cell = new Cell() { Value = item }; row.Cells.Add(cell); } rows.Add(row); @@ -35,7 +35,7 @@ private class Row : IRow private class Cell : ICell { - public string Value { get; set; } + public object Value { get; set; } public string ColumnName { get; set; } } } diff --git a/NBi.Core/Scalar/Casting/CasterFactory.cs b/NBi.Core/Scalar/Casting/CasterFactory.cs index 30a45c3bb..dc8352dc6 100644 --- a/NBi.Core/Scalar/Casting/CasterFactory.cs +++ b/NBi.Core/Scalar/Casting/CasterFactory.cs @@ -29,6 +29,7 @@ public ICaster Instantiate(ColumnType type) { switch (type) { + case ColumnType.Untyped: return new UntypedCaster(); case ColumnType.Text: return new TextCaster(); case ColumnType.Numeric: return new NumericCaster(); case ColumnType.Boolean: return new BooleanCaster(); diff --git a/NBi.Core/Scalar/Casting/UntypedCaster.cs b/NBi.Core/Scalar/Casting/UntypedCaster.cs new file mode 100644 index 000000000..448f0048d --- /dev/null +++ b/NBi.Core/Scalar/Casting/UntypedCaster.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Scalar.Casting +{ + class UntypedCaster : ICaster + { + public object Execute(object value) + => value; + + object ICaster.Execute(object value) => Execute(value); + + public bool IsValid(object value) => true; + } +} diff --git a/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs b/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs index b3fef70ab..92e806396 100644 --- a/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs +++ b/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs @@ -34,7 +34,7 @@ public void Apply_Rows_Success(object[] values, ColumnType columnType, int index var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Min())); } @@ -55,9 +55,9 @@ public void Apply_TopTwo_Success(object[] values, ColumnType columnType, int[] i var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(2)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0].ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0])); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Min())); - Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1].ToString())); + Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1])); Assert.That(filteredRs.Rows[1].ItemArray[1], Is.EqualTo(values.Except(Enumerable.Repeat(values.Min(), 1)).Min())); } @@ -76,11 +76,11 @@ public void Apply_Larger_Success(object[] values, ColumnType columnType, int[] i var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(values.Count())); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0].ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0])); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Min())); - Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1].ToString())); + Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1])); Assert.That(filteredRs.Rows[1].ItemArray[1], Is.EqualTo(values.Except(Enumerable.Repeat(values.Min(), 1)).Min())); - Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[0], Is.EqualTo(index[2].ToString())); + Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[0], Is.EqualTo(index[2])); Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[1], Is.EqualTo(values.Max())); } @@ -101,7 +101,7 @@ public void Apply_Alias_Success(object[] values, ColumnType columnType, int inde var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Min())); } @@ -123,7 +123,7 @@ public void Apply_Exp_Success(object[] values, ColumnType columnType, int index) var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo("125")); } diff --git a/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs b/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs index 7fbb6ba00..c1ae1dbe7 100644 --- a/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs +++ b/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs @@ -21,6 +21,7 @@ public class TopRankingTest [TestCase(new object[] { "100", "120", "110", "130", "105" }, ColumnType.Numeric, 4)] [TestCase(new object[] { "a", "b", "e", "c", "d" }, ColumnType.Text, 3)] [TestCase(new object[] { "2010-02-02 07:12:16.52", "2010-02-02 07:12:16.55", "2010-02-02 08:12:16.50" }, ColumnType.DateTime, 3)] + public void Apply_Rows_Success(object[] values, ColumnType columnType, int index) { var i = 0; @@ -34,7 +35,7 @@ public void Apply_Rows_Success(object[] values, ColumnType columnType, int index var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Max())); } @@ -55,9 +56,9 @@ public void Apply_TopTwo_Success(object[] values, ColumnType columnType, int[] i var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(2)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0].ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0])); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Max())); - Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1].ToString())); + Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1])); Assert.That(filteredRs.Rows[1].ItemArray[1], Is.EqualTo(values.Except(Enumerable.Repeat(values.Max(), 1)).Max())); } @@ -76,11 +77,11 @@ public void Apply_Larger_Success(object[] values, ColumnType columnType, int[] i var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(values.Count())); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0].ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0])); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Max())); - Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1].ToString())); + Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1])); Assert.That(filteredRs.Rows[1].ItemArray[1], Is.EqualTo(values.Except(Enumerable.Repeat(values.Max(), 1)).Max())); - Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[0], Is.EqualTo(index[2].ToString())); + Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[0], Is.EqualTo(index[2])); Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[1], Is.EqualTo(values.Min())); } @@ -102,7 +103,7 @@ public void Apply_Alias_Success(object[] values, ColumnType columnType, int inde var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Max())); } @@ -124,7 +125,7 @@ public void Apply_Exp_Success(object[] values, ColumnType columnType, int index) var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo("139")); } diff --git a/NBi.Testing.Core/ResultSet/Alteration/Lookup/LookupReplaceEngineTest.cs b/NBi.Testing.Core/ResultSet/Alteration/Lookup/LookupReplaceEngineTest.cs index fe7e3b7bb..3462220c8 100644 --- a/NBi.Testing.Core/ResultSet/Alteration/Lookup/LookupReplaceEngineTest.cs +++ b/NBi.Testing.Core/ResultSet/Alteration/Lookup/LookupReplaceEngineTest.cs @@ -54,6 +54,43 @@ public void Execute_AllLookupFound_CorrectReplacement() Assert.That(result.Rows.Cast().Select(x => x[1] as string).Where(x => x != "alpha" && x != "beta"), Is.Empty); } + [Test] + public void Execute_AllLookupFoundSwitchingFromTextToNumeric_CorrectReplacement() + { + var candidate = new ObjectsResultSetResolver( + new ObjectsResultSetResolverArgs( + new[] { + new object[] { 1, "A", 100 }, + new object[] { 2, "B", 101 }, + new object[] { 3, "A", 125 }, + new object[] { 4, "B", 155 } + } + )).Execute(); + + var reference = new ResultSetService( + new ObjectsResultSetResolver( + new ObjectsResultSetResolverArgs( + new[] { + new object[] { "A", 10.2 }, + new object[] { "B", 21.1 }, + } + )).Execute, null); + + var engine = new LookupReplaceEngine( + new LookupReplaceArgs( + reference, + new ColumnMapping(new ColumnOrdinalIdentifier(1), new ColumnOrdinalIdentifier(0), ColumnType.Text), + new ColumnOrdinalIdentifier(1) + )); + + var result = engine.Execute(candidate); + Assert.That(result.Columns.Count, Is.EqualTo(3)); + Assert.That(result.Rows.Count, Is.EqualTo(4)); + Assert.That(result.Rows.Cast().Select(x => x[1]).Distinct(), Does.Contain(10.2)); + Assert.That(result.Rows.Cast().Select(x => x[1]).Distinct(), Does.Contain(21.1)); + Assert.That(result.Rows.Cast().Select(x => Convert.ToDecimal(x[1])).Where(x => x != 10.2m && x != 21.1m), Is.Empty); + } + [Test] public void ExecuteWithFailureStretegy_OneLookupMissing_ExceptionThrown() { diff --git a/NBi.Testing.Core/ResultSet/ResultSetTest.cs b/NBi.Testing.Core/ResultSet/ResultSetTest.cs index a66c654cf..0cd2d1d37 100644 --- a/NBi.Testing.Core/ResultSet/ResultSetTest.cs +++ b/NBi.Testing.Core/ResultSet/ResultSetTest.cs @@ -62,20 +62,20 @@ public void Load_ThreeIRowsWithTwoICells_ThreeRowsAndTwoColumns() var objects = new List { Mock.Of ( x => x.Cells == new List { - Mock.Of( y=> y.Value == "CY 2001"), - Mock.Of( y=> y.Value == "1000") } + Mock.Of(y => (string)(y.Value) == "CY 2001"), + Mock.Of(y => (decimal)(y.Value) == 1000) } ) , Mock.Of( x => x.Cells == new List { - Mock.Of(y=> y.Value == "CY 2002"), - Mock.Of(y => y.Value == "10.4") } + Mock.Of(y => (string)(y.Value) == "CY 2002"), + Mock.Of(y => (decimal)(y.Value) == 10.4m) } ) , Mock.Of( x => x.Cells == new List { - Mock.Of ( y=> y.Value == "CY 2003"), - Mock.Of(y => y.Value == "200") } + Mock.Of(y => (string)(y.Value) == "CY 2003"), + Mock.Of(y => (decimal)(y.Value) == 200) } ) }; @@ -86,7 +86,9 @@ public void Load_ThreeIRowsWithTwoICells_ThreeRowsAndTwoColumns() Assert.That(rs.Rows.Count, Is.EqualTo(3)); Assert.That(rs.Rows[0].ItemArray[0], Is.EqualTo("CY 2001")); - Assert.That(rs.Rows[0].ItemArray[1], Is.EqualTo("1000")); + Assert.That(rs.Rows[0].ItemArray[1], Is.EqualTo(1000)); + Assert.That(rs.Rows[1].ItemArray[0], Is.EqualTo("CY 2002")); + Assert.That(rs.Rows[1].ItemArray[1], Is.EqualTo(10.4)); } [Test] diff --git a/NBi.Xml/Items/ResultSet/CellXml.cs b/NBi.Xml/Items/ResultSet/CellXml.cs index 7cf05d6dc..732180550 100644 --- a/NBi.Xml/Items/ResultSet/CellXml.cs +++ b/NBi.Xml/Items/ResultSet/CellXml.cs @@ -6,14 +6,14 @@ namespace NBi.Xml.Items.ResultSet public class CellXml : ICell { [XmlText] - public string Value { get; set; } + public string StringValue { get; set; } + + [XmlIgnore] + public object Value { get => StringValue; set { StringValue = value.ToString(); } } [XmlAttribute("column-name")] public string ColumnName { get; set; } - public override string ToString() - { - return Value; - } + public override string ToString() => StringValue.ToString(); } }