From f6aa940bac2646dddde12152c659d0a91aed7542 Mon Sep 17 00:00:00 2001 From: ShpakovDaniel <44341164+Reltig@users.noreply.github.com> Date: Sun, 24 Dec 2023 14:33:24 +0500 Subject: [PATCH 1/4] first commit --- ObjectPrinting/Helper.cs | 37 ++++ ObjectPrinting/IBaseConfig.cs | 14 ++ ObjectPrinting/ObjectPrinter.cs | 2 +- ObjectPrinting/ObjectPrinting.csproj | 5 + ObjectPrinting/PrintingConfig.cs | 201 +++++++++++++++--- ObjectPrinting/PrintingExtension.cs | 28 +++ ObjectPrinting/PropertyConfig.cs | 23 ++ .../Tests/ObjectPrinterAcceptanceTests.cs | 27 --- ObjectPrinting/TypeConfig.cs | 22 ++ ObjectPrintingTest/GlobalUsings.cs | 1 + .../ObjectPrinterAcceptanceTests.cs | 157 ++++++++++++++ ObjectPrintingTest/ObjectPrintingTest.csproj | 24 +++ ObjectPrintingTest/TestTypes/Node.cs | 25 +++ .../TestTypes}/Person.cs | 4 +- ObjectPrintingTest/TestTypes/PhoneBook.cs | 13 ++ fluent-api.sln | 6 + 16 files changed, 524 insertions(+), 65 deletions(-) create mode 100644 ObjectPrinting/Helper.cs create mode 100644 ObjectPrinting/IBaseConfig.cs create mode 100644 ObjectPrinting/PrintingExtension.cs create mode 100644 ObjectPrinting/PropertyConfig.cs delete mode 100644 ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs create mode 100644 ObjectPrinting/TypeConfig.cs create mode 100644 ObjectPrintingTest/GlobalUsings.cs create mode 100644 ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs create mode 100644 ObjectPrintingTest/ObjectPrintingTest.csproj create mode 100644 ObjectPrintingTest/TestTypes/Node.cs rename {ObjectPrinting/Tests => ObjectPrintingTest/TestTypes}/Person.cs (80%) create mode 100644 ObjectPrintingTest/TestTypes/PhoneBook.cs diff --git a/ObjectPrinting/Helper.cs b/ObjectPrinting/Helper.cs new file mode 100644 index 00000000..15520d80 --- /dev/null +++ b/ObjectPrinting/Helper.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace ObjectPrinting +{ + public static class Helper + { + public static PropertyInfo GetPropertyInfo(Expression> propertyLambda) + { + if (!(propertyLambda.Body is MemberExpression member)) + { + throw new ArgumentException(string.Format( + "Expression '{0}' refers to a method, not a property.", + propertyLambda.ToString())); + } + + if (!(member.Member is PropertyInfo propInfo)) + { + throw new ArgumentException(string.Format( + "Expression '{0}' refers to a field, not a property.", + propertyLambda.ToString())); + } + + Type type = typeof(TSource); + if (propInfo.ReflectedType != null && type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType)) + { + throw new ArgumentException(string.Format( + "Expression '{0}' refers to a property that is not from type {1}.", + propertyLambda.ToString(), + type)); + } + + return propInfo; + } + } +} \ No newline at end of file diff --git a/ObjectPrinting/IBaseConfig.cs b/ObjectPrinting/IBaseConfig.cs new file mode 100644 index 00000000..4e2867a3 --- /dev/null +++ b/ObjectPrinting/IBaseConfig.cs @@ -0,0 +1,14 @@ +using System; +using System.Linq.Expressions; + +namespace ObjectPrinting +{ + public interface IBaseConfig + { + string PrintToString(TOwner obj); + IBaseConfig Exclude(); + IBaseConfig Exclude(Expression> f); + TypeConfig Printing(); + PropertyConfig Printing(Expression> f); + } +} \ No newline at end of file diff --git a/ObjectPrinting/ObjectPrinter.cs b/ObjectPrinting/ObjectPrinter.cs index 3c7867c3..cabb9a60 100644 --- a/ObjectPrinting/ObjectPrinter.cs +++ b/ObjectPrinting/ObjectPrinter.cs @@ -2,7 +2,7 @@ namespace ObjectPrinting { public class ObjectPrinter { - public static PrintingConfig For() + public static IBaseConfig For() { return new PrintingConfig(); } diff --git a/ObjectPrinting/ObjectPrinting.csproj b/ObjectPrinting/ObjectPrinting.csproj index 1c5eaf1c..5e355d43 100644 --- a/ObjectPrinting/ObjectPrinting.csproj +++ b/ObjectPrinting/ObjectPrinting.csproj @@ -7,8 +7,13 @@ + + + + + diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index a9e08211..bcdaa6b9 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -1,41 +1,174 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; +using System.Reflection; using System.Text; +using NUnit.Framework; namespace ObjectPrinting { - public class PrintingConfig - { - public string PrintToString(TOwner obj) - { - return PrintToString(obj, 0); - } - - private string PrintToString(object obj, int nestingLevel) - { - //TODO apply configurations - if (obj == null) - return "null" + Environment.NewLine; - - var finalTypes = new[] - { - typeof(int), typeof(double), typeof(float), typeof(string), - typeof(DateTime), typeof(TimeSpan) - }; - if (finalTypes.Contains(obj.GetType())) - return obj + Environment.NewLine; - - var identation = new string('\t', nestingLevel + 1); - var sb = new StringBuilder(); - var type = obj.GetType(); - sb.AppendLine(type.Name); - foreach (var propertyInfo in type.GetProperties()) - { - sb.Append(identation + propertyInfo.Name + " = " + - PrintToString(propertyInfo.GetValue(obj), - nestingLevel + 1)); - } - return sb.ToString(); - } - } + public class PrintingConfig : + IBaseConfig + { + private readonly Type[] finalTypes = new[] + { + typeof(int), typeof(double), typeof(float), typeof(string), + typeof(DateTime), typeof(TimeSpan), typeof(Guid) + }; + + private readonly HashSet objects; + + private List excludedTypes; + private List excludedProperties; + + private Dictionary> serializedByType; + private Dictionary> serializedByPropertyInfo; + + public PrintingConfig() + { + objects = new HashSet(); + excludedTypes = new List(); + excludedProperties = new List(); + serializedByType = new Dictionary>(); + serializedByPropertyInfo = new Dictionary>(); + } + + public string PrintToString(TOwner obj) + { + return PrintToString(obj, 0); + } + + private string PrintToString(object obj, int nestingLevel) + { + //TODO apply configurations + if (obj == null) + return "null" + Environment.NewLine; + + if (finalTypes.Contains(obj.GetType())) + return obj + Environment.NewLine; + + if (objects.Contains(obj)) + return "cycled" + Environment.NewLine; + objects.Add(obj); + + var identation = new string('\t', nestingLevel + 1); + var sb = new StringBuilder(); + var type = obj.GetType(); + sb.AppendLine(type.Name); + foreach (var propertyInfo in type.GetProperties()) + { + var propType = propertyInfo.PropertyType; + + if (excludedProperties.Contains(propertyInfo) || excludedTypes.Contains(propType)) + continue; + + if (serializedByPropertyInfo.ContainsKey(propertyInfo)) + { + var serializedValue = serializedByPropertyInfo[propertyInfo](propertyInfo.GetValue(obj)); + sb.Append(identation + propertyInfo.Name + " = " + serializedValue); + continue; + } + + if (serializedByType.ContainsKey(propType)) + { + var serializedValue = serializedByType[propType](propertyInfo.GetValue(obj)); + sb.Append(identation + propertyInfo.Name + " = " + serializedValue); + continue; + } + + if (propType.BaseType == typeof(Array) || propType.GetInterfaces().Contains(typeof(IList))) + { + sb.Append(identation + propertyInfo.Name + ": "); + sb.Append(SerializeListElements(propertyInfo.GetValue(obj), nestingLevel + 1)); + continue; + } + + if (propType.GetInterfaces().Contains(typeof(IDictionary))) + { + sb.Append(identation + propertyInfo.Name + ": "); + sb.Append(SerializeDictionaryElements(propertyInfo.GetValue(obj), nestingLevel + 1)); + continue; + } + + sb.Append(identation + propertyInfo.Name + " = " + + PrintToString(propertyInfo.GetValue(obj), + nestingLevel + 1)); + } + + return sb.ToString(); + } + + private string SerializeDictionaryElements(object obj, int nesting) + { + var sb = new StringBuilder(); + var dictionary = obj as IDictionary; + var identation = new string('\t', nesting + 1); + if (dictionary == null || dictionary.Keys.Count == 0) + return "" + Environment.NewLine; + sb.Append(Environment.NewLine); + var index = 1; + foreach (var element in dictionary.Keys) + { + sb.AppendLine(identation + index++ + " element:"); + sb.Append(identation + "\tKey: " + PrintToString(element, nesting + 2)); + sb.Append(identation + "\tValue: " + PrintToString(dictionary[element], nesting + 2)); + } + + return sb.ToString(); + } + + private string SerializeListElements(object obj, int nesting) + { + var sb = new StringBuilder(); + var list = obj as IEnumerable; + var identation = new string('\t', nesting + 1); + if (list == null || !list.Cast().Any()) + return "" + Environment.NewLine; + sb.Append(Environment.NewLine); + var index = 1; + foreach (var element in list) + { + sb.Append(identation + index++ + ": " + PrintToString(element, nesting + 1)); + } + + return sb.ToString(); + } + + public IBaseConfig Exclude(Expression> f) + { + var configuratedProperty = Helper.GetPropertyInfo(f); + excludedProperties.Add(configuratedProperty); + return this; + } + + public IBaseConfig Exclude() + { + excludedTypes.Add(typeof(T)); + return this; + } + + TypeConfig IBaseConfig.Printing() + { + var configuratedType = typeof(TArg); + return new TypeConfig(this, configuratedType); + } + + public PropertyConfig Printing(Expression> f) + { + var configuratedProperty = Helper.GetPropertyInfo(f); + return new PropertyConfig(this, configuratedProperty); + } + + public void AddPropertySerialization(Func f, PropertyInfo configuratedProperty) + { + serializedByPropertyInfo.Add(configuratedProperty, obj => f((TProperty)obj)); + } + + public void AddTypeSerialization(Func f, Type configuratedType) + { + serializedByType.Add(configuratedType, obj => f((TProperty)obj)); + } + } } \ No newline at end of file diff --git a/ObjectPrinting/PrintingExtension.cs b/ObjectPrinting/PrintingExtension.cs new file mode 100644 index 00000000..7e6768bc --- /dev/null +++ b/ObjectPrinting/PrintingExtension.cs @@ -0,0 +1,28 @@ +using System; +using System.Globalization; + +namespace ObjectPrinting +{ + public static class PrintingExtension + { + public static PrintingConfig Truncate(this PropertyConfig config, int startPos, int length) + { + return config.SerializeAs(s => s.Substring(startPos, length)); + } + + public static PrintingConfig SetCulture(this TypeConfig config, CultureInfo info) + { + return config.SerializeAs(d => d.ToString(info)); + } + + public static PrintingConfig SetCulture(this PropertyConfig config, CultureInfo info) + { + return config.SerializeAs(d => d.ToString(info)); + } + + public static PrintingConfig SetCulture(this TypeConfig config, CultureInfo info) + { + return config.SerializeAs(date => date.ToString(info)); + } + } +} \ No newline at end of file diff --git a/ObjectPrinting/PropertyConfig.cs b/ObjectPrinting/PropertyConfig.cs new file mode 100644 index 00000000..538a91a9 --- /dev/null +++ b/ObjectPrinting/PropertyConfig.cs @@ -0,0 +1,23 @@ +using System; +using System.Reflection; + +namespace ObjectPrinting +{ + public class PropertyConfig + { + private readonly PrintingConfig config; + private readonly PropertyInfo configuratedProperty; + + public PropertyConfig(PrintingConfig config, PropertyInfo configuratedProperty) + { + this.config = config; + this.configuratedProperty = configuratedProperty; + } + + public PrintingConfig SerializeAs(Func f) + { + config.AddPropertySerialization(f, configuratedProperty); + return config; + } + } +} \ No newline at end of file diff --git a/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs b/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs deleted file mode 100644 index 4c8b2445..00000000 --- a/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -using NUnit.Framework; - -namespace ObjectPrinting.Tests -{ - [TestFixture] - public class ObjectPrinterAcceptanceTests - { - [Test] - public void Demo() - { - var person = new Person { Name = "Alex", Age = 19 }; - - var printer = ObjectPrinter.For(); - //1. Исключить из сериализации свойства определенного типа - //2. Указать альтернативный способ сериализации для определенного типа - //3. Для числовых типов указать культуру - //4. Настроить сериализацию конкретного свойства - //5. Настроить обрезание строковых свойств (метод должен быть виден только для строковых свойств) - //6. Исключить из сериализации конкретного свойства - - string s1 = printer.PrintToString(person); - - //7. Синтаксический сахар в виде метода расширения, сериализующего по-умолчанию - //8. ...с конфигурированием - } - } -} \ No newline at end of file diff --git a/ObjectPrinting/TypeConfig.cs b/ObjectPrinting/TypeConfig.cs new file mode 100644 index 00000000..973c19a3 --- /dev/null +++ b/ObjectPrinting/TypeConfig.cs @@ -0,0 +1,22 @@ +using System; + +namespace ObjectPrinting +{ + public class TypeConfig + { + private readonly PrintingConfig config; + private readonly Type configuratedType; + + public TypeConfig(PrintingConfig config, Type configuratedType) + { + this.config = config; + this.configuratedType = configuratedType; + } + + public PrintingConfig SerializeAs(Func f) + { + config.AddTypeSerialization(f, configuratedType); + return config; + } + } +} \ No newline at end of file diff --git a/ObjectPrintingTest/GlobalUsings.cs b/ObjectPrintingTest/GlobalUsings.cs new file mode 100644 index 00000000..cefced49 --- /dev/null +++ b/ObjectPrintingTest/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs new file mode 100644 index 00000000..7f36e6f8 --- /dev/null +++ b/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs @@ -0,0 +1,157 @@ +using System.Security.Cryptography; +using FluentAssertions; +using NUnit.Framework; +using ObjectPrintingTest; +using ObjectPrintingTest.TestTypes; + +namespace ObjectPrinting.Tests +{ + [TestFixture] + public class ObjectPrinterAcceptanceTests + { + private IBaseConfig printer; + [SetUp] + public void SetUp() + { + printer = ObjectPrinter.For(); + } + + [Test] + public void ExcludeType() + { + var person = new Person { Name = "Alex", Age = 19}; + printer + .Exclude() + .Exclude() + .PrintToString(person) + .Should() + .NotContainAll("Height", "Age"); + } + + [Test] + public void ExcludeProperty() + { + var person = new Person { Name = "Alex", Age = 19 }; + printer + .Exclude(p => p.Name) + .Exclude(p => p.Age) + .PrintToString(person) + .Should() + .NotContainAll(new [] { "Name", "Age" }); + } + + [Test] + public void SerializeType() + { + var person = new Person { Name = "Alex", Age = 19 }; + printer + .Printing() + .SerializeAs(s => s+s) + .PrintToString(person) + .Should() + .Contain("Name = AlexAlex"); + } + + [Test] + public void SerializeProperty() + { + var person = new Person { Name = "Alex", Age = 19 }; + printer + .Printing(p => p.Age) + .SerializeAs(age => $"{age*3}") + .PrintToString(person) + .Should() + .Contain("Age = 57"); + } + + [Test] + public void Truncate() + { + var person = new Person { Name = "Alex", Age = 19 }; + printer + .Printing( p => p.Name) + .Truncate(1, 3) + .PrintToString(person) + .Should() + .Contain("Name = lex"); + } + + [Test] + public void CultureInfoForType() + { + var person = new Person { Name = "Alex", Age = 19, Height = 1.23}; + printer + .Printing() + .SetCulture(System.Globalization.CultureInfo.CurrentCulture) + .PrintToString(person) + .Should() + .Contain("Height = 1,23"); + } + + [Test] + public void CultureInfoForProperty() + { + var person = new Person { Name = "Alex", Age = 19, Height = 1.23}; + printer + .Printing(p => p.Height) + .SetCulture(System.Globalization.CultureInfo.CurrentCulture) + .PrintToString(person) + .Should() + .Contain("Height = 1,23"); + } + + [Test] + public void PrintList() + { + var node = new Node( + "A", + new List + { + new Node("B"), + new Node( + "C", + new List() + { + new Node("D"), + new Node("E") + } + ) + }); + var result = ObjectPrinter.For().PrintToString(node); + Console.WriteLine(result); + result + .Should() + .Be("Node\r\n\tName = A\r\n\tNodes: \r\n\t\t1: Node\r\n\t\t\tName = B\r\n\t\t\tNodes: \r\n\t\t2: Node\r\n\t\t\tName = C\r\n\t\t\tNodes: \r\n\t\t\t\t1: Node\r\n\t\t\t\t\tName = D\r\n\t\t\t\t\tNodes: \r\n\t\t\t\t2: Node\r\n\t\t\t\t\tName = E\r\n\t\t\t\t\tNodes: \r\n"); + } + + [Test] + public void PrintDictionaries() + { + var phone = new PhoneBook( + "New York", + new Dictionary() + { + { "+1 (646) 555-3456", new Person(){Name="John Doe", Age = 30} }, + { "+1 (646) 555-4567", new Person(){Name="Jane Doe", Age = 30} } + } + ); + var result = ObjectPrinter.For().PrintToString(phone); + Console.WriteLine(result); + result + .Should() + .Be("PhoneBook\r\n\tTown = New York\r\n\tNumberToPerson: \r\n\t\t1 element:\r\n\t\t\tKey: +1 (646) 555-3456\r\n\t\t\tValue: Person\r\n\t\t\t\tId = 00000000-0000-0000-0000-000000000000\r\n\t\t\t\tName = John Doe\r\n\t\t\t\tHeight = 0\r\n\t\t\t\tAge = 30\r\n\t\t2 element:\r\n\t\t\tKey: +1 (646) 555-4567\r\n\t\t\tValue: Person\r\n\t\t\t\tId = 00000000-0000-0000-0000-000000000000\r\n\t\t\t\tName = Jane Doe\r\n\t\t\t\tHeight = 0\r\n\t\t\t\tAge = 30\r\n"); + } + + [Test] + public void Cycled() + { + var node = new Node("A").Add(new Node("B")); + node.Add(node); + var result = ObjectPrinter.For().PrintToString(node); + Console.WriteLine(result); + result + .Should() + .Be("Node\r\n\tName = A\r\n\tNodes: \r\n\t\t1: Node\r\n\t\t\tName = B\r\n\t\t\tNodes: \r\n\t\t2: cycled\r\n"); + } + } +} \ No newline at end of file diff --git a/ObjectPrintingTest/ObjectPrintingTest.csproj b/ObjectPrintingTest/ObjectPrintingTest.csproj new file mode 100644 index 00000000..5fd944c9 --- /dev/null +++ b/ObjectPrintingTest/ObjectPrintingTest.csproj @@ -0,0 +1,24 @@ + + + + net7.0 + enable + enable + + false + true + + + + + + + + + + + + + + + diff --git a/ObjectPrintingTest/TestTypes/Node.cs b/ObjectPrintingTest/TestTypes/Node.cs new file mode 100644 index 00000000..0b2cb4de --- /dev/null +++ b/ObjectPrintingTest/TestTypes/Node.cs @@ -0,0 +1,25 @@ +namespace ObjectPrintingTest.TestTypes; + +public class Node +{ + public string Name { get; set; } + public List Nodes { get; private set; } + + public Node(string name) + { + Name = name; + Nodes = new List(); + } + + public Node(string name, List nodes) + { + Name = name; + Nodes = nodes; + } + + public Node Add(Node node) + { + Nodes.Add(node); + return this; + } +} \ No newline at end of file diff --git a/ObjectPrinting/Tests/Person.cs b/ObjectPrintingTest/TestTypes/Person.cs similarity index 80% rename from ObjectPrinting/Tests/Person.cs rename to ObjectPrintingTest/TestTypes/Person.cs index f9555955..9e344601 100644 --- a/ObjectPrinting/Tests/Person.cs +++ b/ObjectPrintingTest/TestTypes/Person.cs @@ -1,6 +1,4 @@ -using System; - -namespace ObjectPrinting.Tests +namespace ObjectPrintingTest.TestTypes { public class Person { diff --git a/ObjectPrintingTest/TestTypes/PhoneBook.cs b/ObjectPrintingTest/TestTypes/PhoneBook.cs new file mode 100644 index 00000000..f9cc86ef --- /dev/null +++ b/ObjectPrintingTest/TestTypes/PhoneBook.cs @@ -0,0 +1,13 @@ +namespace ObjectPrintingTest.TestTypes; + +public class PhoneBook +{ + public PhoneBook(string town, Dictionary numberToPerson) + { + Town = town; + NumberToPerson = numberToPerson; + } + + public string Town { get; set; } + public Dictionary NumberToPerson { get; set; } +} \ No newline at end of file diff --git a/fluent-api.sln b/fluent-api.sln index 69c8db9e..c4ebcd5a 100644 --- a/fluent-api.sln +++ b/fluent-api.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentMapping.Tests", "Samp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spectacle", "Samples\Spectacle\Spectacle.csproj", "{EFA9335C-411B-4597-B0B6-5438D1AE04C3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectPrintingTest", "ObjectPrintingTest\ObjectPrintingTest.csproj", "{BAF4655C-D2BF-410C-90E3-02E09668406C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -35,6 +37,10 @@ Global {EFA9335C-411B-4597-B0B6-5438D1AE04C3}.Debug|Any CPU.Build.0 = Debug|Any CPU {EFA9335C-411B-4597-B0B6-5438D1AE04C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {EFA9335C-411B-4597-B0B6-5438D1AE04C3}.Release|Any CPU.Build.0 = Release|Any CPU + {BAF4655C-D2BF-410C-90E3-02E09668406C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAF4655C-D2BF-410C-90E3-02E09668406C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAF4655C-D2BF-410C-90E3-02E09668406C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAF4655C-D2BF-410C-90E3-02E09668406C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From a41ebc651f5e52025478bfbb0c462181b29bea24 Mon Sep 17 00:00:00 2001 From: ShpakovDaniel <44341164+Reltig@users.noreply.github.com> Date: Mon, 25 Dec 2023 15:20:39 +0500 Subject: [PATCH 2/4] fix --- ObjectPrinting/Helper.cs | 26 +- ObjectPrinting/ObjectPrinting.csproj | 6 +- ObjectPrinting/PrintingConfig.cs | 295 +++++++++--------- ObjectPrinting/PrintingExtension.cs | 47 ++- .../ObjectPrinterAcceptanceTests.cs | 134 +++++--- ObjectPrintingTest/ObjectPrintingTest.csproj | 1 + .../FluentMapping.Tests.csproj | 2 +- Samples/FluentMapper/FluentMapping.csproj | 2 +- Samples/Spectacle/Spectacle.csproj | 2 +- 9 files changed, 298 insertions(+), 217 deletions(-) diff --git a/ObjectPrinting/Helper.cs b/ObjectPrinting/Helper.cs index 15520d80..b8eb9964 100644 --- a/ObjectPrinting/Helper.cs +++ b/ObjectPrinting/Helper.cs @@ -6,29 +6,25 @@ namespace ObjectPrinting { public static class Helper { - public static PropertyInfo GetPropertyInfo(Expression> propertyLambda) + public static PropertyInfo GetPropertyInfo( + Expression> propertyLambda) { - if (!(propertyLambda.Body is MemberExpression member)) + if (propertyLambda.Body is not MemberExpression member) { - throw new ArgumentException(string.Format( - "Expression '{0}' refers to a method, not a property.", - propertyLambda.ToString())); + throw new ArgumentException($"Expression '{propertyLambda}' refers to a method, not a property."); } - if (!(member.Member is PropertyInfo propInfo)) + if (member.Member is not PropertyInfo propInfo) { - throw new ArgumentException(string.Format( - "Expression '{0}' refers to a field, not a property.", - propertyLambda.ToString())); + throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property."); } - Type type = typeof(TSource); - if (propInfo.ReflectedType != null && type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType)) + var type = typeof(TSource); + if (propInfo.ReflectedType != null && type != propInfo.ReflectedType && + !type.IsSubclassOf(propInfo.ReflectedType)) { - throw new ArgumentException(string.Format( - "Expression '{0}' refers to a property that is not from type {1}.", - propertyLambda.ToString(), - type)); + throw new ArgumentException( + $"Expression '{propertyLambda}' refers to a property that is not from type {type}."); } return propInfo; diff --git a/ObjectPrinting/ObjectPrinting.csproj b/ObjectPrinting/ObjectPrinting.csproj index 5e355d43..a80abb23 100644 --- a/ObjectPrinting/ObjectPrinting.csproj +++ b/ObjectPrinting/ObjectPrinting.csproj @@ -1,7 +1,7 @@  - 8 + latest netcoreapp3.1 false @@ -12,8 +12,4 @@ - - - - diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index bcdaa6b9..278dce5d 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -5,170 +5,169 @@ using System.Linq.Expressions; using System.Reflection; using System.Text; -using NUnit.Framework; namespace ObjectPrinting { - public class PrintingConfig : - IBaseConfig - { - private readonly Type[] finalTypes = new[] - { - typeof(int), typeof(double), typeof(float), typeof(string), - typeof(DateTime), typeof(TimeSpan), typeof(Guid) - }; + public class PrintingConfig : + IBaseConfig + { + private readonly Type[] finalTypes = new[] + { + typeof(int), typeof(double), typeof(float), typeof(string), + typeof(DateTime), typeof(TimeSpan), typeof(Guid) + }; private readonly HashSet objects; - private List excludedTypes; - private List excludedProperties; + private readonly List excludedTypes; + private readonly List excludedProperties; - private Dictionary> serializedByType; - private Dictionary> serializedByPropertyInfo; + private readonly Dictionary> serializedByType; + private readonly Dictionary> serializedByPropertyInfo; - public PrintingConfig() - { + public PrintingConfig() + { objects = new HashSet(); excludedTypes = new List(); - excludedProperties = new List(); - serializedByType = new Dictionary>(); - serializedByPropertyInfo = new Dictionary>(); - } + excludedProperties = new List(); + serializedByType = new Dictionary>(); + serializedByPropertyInfo = new Dictionary>(); + } - public string PrintToString(TOwner obj) - { - return PrintToString(obj, 0); - } + public string PrintToString(TOwner obj) + { + objects.Clear(); + return PrintToString(obj, 0); + } - private string PrintToString(object obj, int nestingLevel) - { - //TODO apply configurations - if (obj == null) - return "null" + Environment.NewLine; + private string PrintToString(object obj, int nestingLevel) + { + if (obj == null) + return "null" + Environment.NewLine; - if (finalTypes.Contains(obj.GetType())) - return obj + Environment.NewLine; + if (finalTypes.Contains(obj.GetType())) + return obj + Environment.NewLine; if (objects.Contains(obj)) return "cycled" + Environment.NewLine; objects.Add(obj); - var identation = new string('\t', nestingLevel + 1); - var sb = new StringBuilder(); - var type = obj.GetType(); - sb.AppendLine(type.Name); - foreach (var propertyInfo in type.GetProperties()) - { - var propType = propertyInfo.PropertyType; - - if (excludedProperties.Contains(propertyInfo) || excludedTypes.Contains(propType)) - continue; - - if (serializedByPropertyInfo.ContainsKey(propertyInfo)) - { - var serializedValue = serializedByPropertyInfo[propertyInfo](propertyInfo.GetValue(obj)); - sb.Append(identation + propertyInfo.Name + " = " + serializedValue); - continue; - } - - if (serializedByType.ContainsKey(propType)) - { - var serializedValue = serializedByType[propType](propertyInfo.GetValue(obj)); - sb.Append(identation + propertyInfo.Name + " = " + serializedValue); - continue; - } - - if (propType.BaseType == typeof(Array) || propType.GetInterfaces().Contains(typeof(IList))) - { - sb.Append(identation + propertyInfo.Name + ": "); - sb.Append(SerializeListElements(propertyInfo.GetValue(obj), nestingLevel + 1)); - continue; - } - - if (propType.GetInterfaces().Contains(typeof(IDictionary))) - { - sb.Append(identation + propertyInfo.Name + ": "); - sb.Append(SerializeDictionaryElements(propertyInfo.GetValue(obj), nestingLevel + 1)); - continue; - } - - sb.Append(identation + propertyInfo.Name + " = " + - PrintToString(propertyInfo.GetValue(obj), - nestingLevel + 1)); - } - - return sb.ToString(); - } - - private string SerializeDictionaryElements(object obj, int nesting) - { - var sb = new StringBuilder(); - var dictionary = obj as IDictionary; - var identation = new string('\t', nesting + 1); - if (dictionary == null || dictionary.Keys.Count == 0) - return "" + Environment.NewLine; - sb.Append(Environment.NewLine); - var index = 1; - foreach (var element in dictionary.Keys) - { - sb.AppendLine(identation + index++ + " element:"); - sb.Append(identation + "\tKey: " + PrintToString(element, nesting + 2)); - sb.Append(identation + "\tValue: " + PrintToString(dictionary[element], nesting + 2)); - } - - return sb.ToString(); - } - - private string SerializeListElements(object obj, int nesting) - { - var sb = new StringBuilder(); - var list = obj as IEnumerable; - var identation = new string('\t', nesting + 1); - if (list == null || !list.Cast().Any()) - return "" + Environment.NewLine; - sb.Append(Environment.NewLine); - var index = 1; - foreach (var element in list) - { - sb.Append(identation + index++ + ": " + PrintToString(element, nesting + 1)); - } - - return sb.ToString(); - } - - public IBaseConfig Exclude(Expression> f) - { - var configuratedProperty = Helper.GetPropertyInfo(f); - excludedProperties.Add(configuratedProperty); - return this; - } - - public IBaseConfig Exclude() - { - excludedTypes.Add(typeof(T)); - return this; - } - - TypeConfig IBaseConfig.Printing() - { - var configuratedType = typeof(TArg); - return new TypeConfig(this, configuratedType); - } - - public PropertyConfig Printing(Expression> f) - { - var configuratedProperty = Helper.GetPropertyInfo(f); - return new PropertyConfig(this, configuratedProperty); - } - - public void AddPropertySerialization(Func f, PropertyInfo configuratedProperty) - { - serializedByPropertyInfo.Add(configuratedProperty, obj => f((TProperty)obj)); - } - - public void AddTypeSerialization(Func f, Type configuratedType) - { - serializedByType.Add(configuratedType, obj => f((TProperty)obj)); - } - } + var identation = new string('\t', nestingLevel + 1); + var sb = new StringBuilder(); + var type = obj.GetType(); + sb.AppendLine(type.Name); + foreach (var propertyInfo in type.GetProperties()) + { + var propType = propertyInfo.PropertyType; + + if (excludedProperties.Contains(propertyInfo) || excludedTypes.Contains(propType)) + continue; + + if (serializedByPropertyInfo.TryGetValue(propertyInfo, out var propertySerialization)) + { + var serializedValue = propertySerialization(propertyInfo.GetValue(obj)); + sb.Append(identation + propertyInfo.Name + " = " + serializedValue); + continue; + } + + if (serializedByType.TryGetValue(propType, out var typeSerialization)) + { + var serializedValue = typeSerialization(propertyInfo.GetValue(obj)); + sb.Append(identation + propertyInfo.Name + " = " + serializedValue); + continue; + } + + if (propType.GetInterfaces().Contains(typeof(IList))) + { + sb.Append(identation + propertyInfo.Name + ": "); + sb.Append(SerializeListElements(propertyInfo.GetValue(obj), nestingLevel + 1)); + continue; + } + + if (propType.GetInterfaces().Contains(typeof(IDictionary))) + { + sb.Append(identation + propertyInfo.Name + ": "); + sb.Append(SerializeDictionaryElements(propertyInfo.GetValue(obj), nestingLevel + 1)); + continue; + } + + sb.Append(identation + propertyInfo.Name + " = " + + PrintToString(propertyInfo.GetValue(obj), + nestingLevel + 1)); + } + + return sb.ToString(); + } + + private string SerializeDictionaryElements(object obj, int nesting) + { + var sb = new StringBuilder(); + var dictionary = obj as IDictionary; + var identation = new string('\t', nesting + 1); + if (dictionary == null || dictionary.Keys.Count == 0) + return "" + Environment.NewLine; + sb.Append(Environment.NewLine); + var index = 0; + foreach (var element in dictionary.Keys) + { + sb.AppendLine(identation + index++ + " element:"); + sb.Append(identation + "\tKey: " + PrintToString(element, nesting + 2)); + sb.Append(identation + "\tValue: " + PrintToString(dictionary[element], nesting + 2)); + } + + return sb.ToString(); + } + + private string SerializeListElements(object obj, int nesting) + { + var sb = new StringBuilder(); + var list = obj as IEnumerable; + var identation = new string('\t', nesting + 1); + if (list == null || !list.Cast().Any()) + return "" + Environment.NewLine; + sb.Append(Environment.NewLine); + var index = 0; + foreach (var element in list) + { + sb.Append(identation + index++ + ": " + PrintToString(element, nesting + 1)); + } + + return sb.ToString(); + } + + public IBaseConfig Exclude(Expression> f) + { + var configuratedProperty = Helper.GetPropertyInfo(f); + excludedProperties.Add(configuratedProperty); + return this; + } + + public IBaseConfig Exclude() + { + excludedTypes.Add(typeof(T)); + return this; + } + + public TypeConfig Printing() + { + var configuratedType = typeof(TArg); + return new TypeConfig(this, configuratedType); + } + + public PropertyConfig Printing(Expression> f) + { + var configuratedProperty = Helper.GetPropertyInfo(f); + return new PropertyConfig(this, configuratedProperty); + } + + public void AddPropertySerialization(Func f, PropertyInfo configuratedProperty) + { + serializedByPropertyInfo.Add(configuratedProperty, obj => f((TProperty)obj)); + } + + public void AddTypeSerialization(Func f, Type configuratedType) + { + serializedByType.Add(configuratedType, obj => f((TProperty)obj)); + } + } } \ No newline at end of file diff --git a/ObjectPrinting/PrintingExtension.cs b/ObjectPrinting/PrintingExtension.cs index 7e6768bc..b628f7ae 100644 --- a/ObjectPrinting/PrintingExtension.cs +++ b/ObjectPrinting/PrintingExtension.cs @@ -5,22 +5,55 @@ namespace ObjectPrinting { public static class PrintingExtension { - public static PrintingConfig Truncate(this PropertyConfig config, int startPos, int length) + public static PrintingConfig Truncate(this PropertyConfig config, int startPos, + int length) { return config.SerializeAs(s => s.Substring(startPos, length)); } - - public static PrintingConfig SetCulture(this TypeConfig config, CultureInfo info) + + public static PrintingConfig SetCulture(this TypeConfig config, + CultureInfo info) { return config.SerializeAs(d => d.ToString(info)); } - - public static PrintingConfig SetCulture(this PropertyConfig config, CultureInfo info) + + public static PrintingConfig SetCulture(this PropertyConfig config, + CultureInfo info) { return config.SerializeAs(d => d.ToString(info)); } - - public static PrintingConfig SetCulture(this TypeConfig config, CultureInfo info) + + public static PrintingConfig SetCulture(this TypeConfig config, + CultureInfo info) + { + return config.SerializeAs(date => date.ToString(info)); + } + + public static PrintingConfig SetCulture(this PropertyConfig config, + CultureInfo info) + { + return config.SerializeAs(date => date.ToString(info)); + } + + public static PrintingConfig SetCulture(this TypeConfig config, + CultureInfo info) + { + return config.SerializeAs(date => date.ToString(info)); + } + + public static PrintingConfig SetCulture(this PropertyConfig config, + CultureInfo info) + { + return config.SerializeAs(date => date.ToString(info)); + } + + public static PrintingConfig SetCulture(this TypeConfig config, CultureInfo info) + { + return config.SerializeAs(date => date.ToString(info)); + } + + public static PrintingConfig SetCulture(this PropertyConfig config, + CultureInfo info) { return config.SerializeAs(date => date.ToString(info)); } diff --git a/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs index 7f36e6f8..d26665f2 100644 --- a/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs @@ -1,113 +1,121 @@ -using System.Security.Cryptography; +using System.Globalization; using FluentAssertions; -using NUnit.Framework; -using ObjectPrintingTest; +using ObjectPrinting; using ObjectPrintingTest.TestTypes; -namespace ObjectPrinting.Tests +namespace ObjectPrintingTest { [TestFixture] public class ObjectPrinterAcceptanceTests { - private IBaseConfig printer; + private IBaseConfig sut; + [SetUp] public void SetUp() { - printer = ObjectPrinter.For(); + sut = ObjectPrinter.For(); } [Test] public void ExcludeType() { - var person = new Person { Name = "Alex", Age = 19}; - printer + var person = new Person { Name = "Alex", Age = 19, Height = 1.23 }; + sut .Exclude() .Exclude() .PrintToString(person) .Should() .NotContainAll("Height", "Age"); } - + [Test] public void ExcludeProperty() { var person = new Person { Name = "Alex", Age = 19 }; - printer + sut .Exclude(p => p.Name) .Exclude(p => p.Age) .PrintToString(person) .Should() - .NotContainAll(new [] { "Name", "Age" }); + .NotContainAll(new[] { "Name", "Age" }); } - + [Test] public void SerializeType() { var person = new Person { Name = "Alex", Age = 19 }; - printer + sut .Printing() - .SerializeAs(s => s+s) + .SerializeAs(s => s + s) .PrintToString(person) .Should() .Contain("Name = AlexAlex"); } - + [Test] public void SerializeProperty() { var person = new Person { Name = "Alex", Age = 19 }; - printer + sut .Printing(p => p.Age) - .SerializeAs(age => $"{age*3}") + .SerializeAs(age => $"{age * 3}") .PrintToString(person) .Should() .Contain("Age = 57"); } - + [Test] public void Truncate() { var person = new Person { Name = "Alex", Age = 19 }; - printer - .Printing( p => p.Name) + sut + .Printing(p => p.Name) .Truncate(1, 3) .PrintToString(person) .Should() .Contain("Name = lex"); } - + [Test] public void CultureInfoForType() { - var person = new Person { Name = "Alex", Age = 19, Height = 1.23}; - printer - .Printing() - .SetCulture(System.Globalization.CultureInfo.CurrentCulture) + var person = new Person { Name = "Alex", Age = 19, Height = 1.23 }; + sut .PrintToString(person) .Should() .Contain("Height = 1,23"); + sut + .Printing() + .SetCulture(CultureInfo.InvariantCulture) + .PrintToString(person) + .Should() + .Contain("Height = 1.23"); } - + [Test] public void CultureInfoForProperty() { - var person = new Person { Name = "Alex", Age = 19, Height = 1.23}; - printer - .Printing(p => p.Height) - .SetCulture(System.Globalization.CultureInfo.CurrentCulture) + var person = new Person { Name = "Alex", Age = 19, Height = 1.23 }; + sut .PrintToString(person) .Should() .Contain("Height = 1,23"); + sut + .Printing(p => p.Height) + .SetCulture(CultureInfo.InvariantCulture) + .PrintToString(person) + .Should() + .Contain("Height = 1.23"); } - + [Test] public void PrintList() { var node = new Node( - "A", + "A", new List { - new Node("B"), + new Node("B"), new Node( "C", new List() @@ -121,9 +129,27 @@ public void PrintList() Console.WriteLine(result); result .Should() - .Be("Node\r\n\tName = A\r\n\tNodes: \r\n\t\t1: Node\r\n\t\t\tName = B\r\n\t\t\tNodes: \r\n\t\t2: Node\r\n\t\t\tName = C\r\n\t\t\tNodes: \r\n\t\t\t\t1: Node\r\n\t\t\t\t\tName = D\r\n\t\t\t\t\tNodes: \r\n\t\t\t\t2: Node\r\n\t\t\t\t\tName = E\r\n\t\t\t\t\tNodes: \r\n"); + .Be( + """ + Node + Name = A + Nodes: + 0: Node + Name = B + Nodes: + 1: Node + Name = C + Nodes: + 0: Node + Name = D + Nodes: + 1: Node + Name = E + Nodes: + + """); } - + [Test] public void PrintDictionaries() { @@ -131,15 +157,35 @@ public void PrintDictionaries() "New York", new Dictionary() { - { "+1 (646) 555-3456", new Person(){Name="John Doe", Age = 30} }, - { "+1 (646) 555-4567", new Person(){Name="Jane Doe", Age = 30} } + { "+1 (646) 555-3456", new Person() { Name = "John Doe", Age = 30 } }, + { "+1 (646) 555-4567", new Person() { Name = "Jane Doe", Age = 30 } } } ); var result = ObjectPrinter.For().PrintToString(phone); Console.WriteLine(result); result .Should() - .Be("PhoneBook\r\n\tTown = New York\r\n\tNumberToPerson: \r\n\t\t1 element:\r\n\t\t\tKey: +1 (646) 555-3456\r\n\t\t\tValue: Person\r\n\t\t\t\tId = 00000000-0000-0000-0000-000000000000\r\n\t\t\t\tName = John Doe\r\n\t\t\t\tHeight = 0\r\n\t\t\t\tAge = 30\r\n\t\t2 element:\r\n\t\t\tKey: +1 (646) 555-4567\r\n\t\t\tValue: Person\r\n\t\t\t\tId = 00000000-0000-0000-0000-000000000000\r\n\t\t\t\tName = Jane Doe\r\n\t\t\t\tHeight = 0\r\n\t\t\t\tAge = 30\r\n"); + .Be( + """ + PhoneBook + Town = New York + NumberToPerson: + 0 element: + Key: +1 (646) 555-3456 + Value: Person + Id = 00000000-0000-0000-0000-000000000000 + Name = John Doe + Height = 0 + Age = 30 + 1 element: + Key: +1 (646) 555-4567 + Value: Person + Id = 00000000-0000-0000-0000-000000000000 + Name = Jane Doe + Height = 0 + Age = 30 + + """); } [Test] @@ -151,7 +197,17 @@ public void Cycled() Console.WriteLine(result); result .Should() - .Be("Node\r\n\tName = A\r\n\tNodes: \r\n\t\t1: Node\r\n\t\t\tName = B\r\n\t\t\tNodes: \r\n\t\t2: cycled\r\n"); + .Be( + """ + Node + Name = A + Nodes: + 0: Node + Name = B + Nodes: + 1: cycled + + """); } } } \ No newline at end of file diff --git a/ObjectPrintingTest/ObjectPrintingTest.csproj b/ObjectPrintingTest/ObjectPrintingTest.csproj index 5fd944c9..085ca480 100644 --- a/ObjectPrintingTest/ObjectPrintingTest.csproj +++ b/ObjectPrintingTest/ObjectPrintingTest.csproj @@ -7,6 +7,7 @@ false true + latest diff --git a/Samples/FluentMapper.Tests/FluentMapping.Tests.csproj b/Samples/FluentMapper.Tests/FluentMapping.Tests.csproj index 0d5262d4..08ab415a 100644 --- a/Samples/FluentMapper.Tests/FluentMapping.Tests.csproj +++ b/Samples/FluentMapper.Tests/FluentMapping.Tests.csproj @@ -1,7 +1,7 @@  - 8 + latest netcoreapp3.1 false diff --git a/Samples/FluentMapper/FluentMapping.csproj b/Samples/FluentMapper/FluentMapping.csproj index d7f3a084..b871c4c9 100644 --- a/Samples/FluentMapper/FluentMapping.csproj +++ b/Samples/FluentMapper/FluentMapping.csproj @@ -1,7 +1,7 @@  - 8 + latest netcoreapp3.1 false diff --git a/Samples/Spectacle/Spectacle.csproj b/Samples/Spectacle/Spectacle.csproj index 6fcb3e8a..dc02c463 100644 --- a/Samples/Spectacle/Spectacle.csproj +++ b/Samples/Spectacle/Spectacle.csproj @@ -1,7 +1,7 @@  - 8 + latest netcoreapp3.1 Exe SpectacleSample From 41ed07626df4f4d1f1755d67276cf0223be3ad49 Mon Sep 17 00:00:00 2001 From: ShpakovDaniel <44341164+Reltig@users.noreply.github.com> Date: Mon, 25 Dec 2023 17:02:49 +0500 Subject: [PATCH 3/4] set culture now works for all IFormattable types --- ObjectPrinting/PrintingExtension.cs | 58 +++++-------------- .../ObjectPrinterAcceptanceTests.cs | 12 ++-- 2 files changed, 21 insertions(+), 49 deletions(-) diff --git a/ObjectPrinting/PrintingExtension.cs b/ObjectPrinting/PrintingExtension.cs index b628f7ae..c1e51982 100644 --- a/ObjectPrinting/PrintingExtension.cs +++ b/ObjectPrinting/PrintingExtension.cs @@ -5,57 +5,29 @@ namespace ObjectPrinting { public static class PrintingExtension { - public static PrintingConfig Truncate(this PropertyConfig config, int startPos, - int length) + public static PrintingConfig Truncate( + this PropertyConfig config, + int startPos, + int length + ) { return config.SerializeAs(s => s.Substring(startPos, length)); } - public static PrintingConfig SetCulture(this TypeConfig config, - CultureInfo info) + public static PrintingConfig SetCulture( + this TypeConfig config, + CultureInfo info + ) where TResult : IFormattable { - return config.SerializeAs(d => d.ToString(info)); + return config.SerializeAs(obj => obj.ToString("", info)); } - public static PrintingConfig SetCulture(this PropertyConfig config, - CultureInfo info) + public static PrintingConfig SetCulture( + this PropertyConfig config, + CultureInfo info + ) where TResult : IFormattable { - return config.SerializeAs(d => d.ToString(info)); - } - - public static PrintingConfig SetCulture(this TypeConfig config, - CultureInfo info) - { - return config.SerializeAs(date => date.ToString(info)); - } - - public static PrintingConfig SetCulture(this PropertyConfig config, - CultureInfo info) - { - return config.SerializeAs(date => date.ToString(info)); - } - - public static PrintingConfig SetCulture(this TypeConfig config, - CultureInfo info) - { - return config.SerializeAs(date => date.ToString(info)); - } - - public static PrintingConfig SetCulture(this PropertyConfig config, - CultureInfo info) - { - return config.SerializeAs(date => date.ToString(info)); - } - - public static PrintingConfig SetCulture(this TypeConfig config, CultureInfo info) - { - return config.SerializeAs(date => date.ToString(info)); - } - - public static PrintingConfig SetCulture(this PropertyConfig config, - CultureInfo info) - { - return config.SerializeAs(date => date.ToString(info)); + return config.SerializeAs(obj => obj.ToString("", info)); } } } \ No newline at end of file diff --git a/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs index d26665f2..198db0d1 100644 --- a/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTest/ObjectPrinterAcceptanceTests.cs @@ -77,7 +77,7 @@ public void Truncate() } [Test] - public void CultureInfoForType() + public void CultureInfoForIFormattableType() { var person = new Person { Name = "Alex", Age = 19, Height = 1.23 }; sut @@ -93,7 +93,7 @@ public void CultureInfoForType() } [Test] - public void CultureInfoForProperty() + public void CultureInfoForIFormattableProperty() { var person = new Person { Name = "Alex", Age = 19, Height = 1.23 }; sut @@ -133,13 +133,13 @@ public void PrintList() """ Node Name = A - Nodes: + Nodes: 0: Node Name = B Nodes: 1: Node Name = C - Nodes: + Nodes: 0: Node Name = D Nodes: @@ -169,7 +169,7 @@ public void PrintDictionaries() """ PhoneBook Town = New York - NumberToPerson: + NumberToPerson: 0 element: Key: +1 (646) 555-3456 Value: Person @@ -201,7 +201,7 @@ public void Cycled() """ Node Name = A - Nodes: + Nodes: 0: Node Name = B Nodes: From a2186387063c76d43c35d2973ae959136d5a8e88 Mon Sep 17 00:00:00 2001 From: ShpakovDaniel <44341164+Reltig@users.noreply.github.com> Date: Tue, 26 Dec 2023 16:09:00 +0500 Subject: [PATCH 4/4] change cast from IEnumerable to IList --- ObjectPrinting/PrintingConfig.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index 278dce5d..ea4fa696 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -121,9 +121,9 @@ private string SerializeDictionaryElements(object obj, int nesting) private string SerializeListElements(object obj, int nesting) { var sb = new StringBuilder(); - var list = obj as IEnumerable; + var list = obj as IList; var identation = new string('\t', nesting + 1); - if (list == null || !list.Cast().Any()) + if (list == null || list.Count == 0) return "" + Environment.NewLine; sb.Append(Environment.NewLine); var index = 0;