From f86b0386236748853ae5977505f3486729df9e34 Mon Sep 17 00:00:00 2001 From: m1nus0ne Date: Fri, 13 Dec 2024 17:06:57 +0500 Subject: [PATCH] first attempt --- ObjectPrinting/ObjectPrintingExtension.cs | 15 ++ ObjectPrinting/PrintingConfig.cs | 174 +++++++++++++++-- ObjectPrinting/PropertyPrintingConfig.cs | 30 +++ .../PropertyPrintingConfigExtension.cs | 18 ++ ObjectPrinting/Solved/ObjectExtensions.cs | 10 - ObjectPrinting/Solved/ObjectPrinter.cs | 10 - ObjectPrinting/Solved/PrintingConfig.cs | 62 ------ .../Solved/PropertyPrintingConfig.cs | 32 --- .../PropertyPrintingConfigExtensions.cs | 18 -- .../Tests/ObjectPrinterAcceptanceTests.cs | 40 ---- ObjectPrinting/Solved/Tests/Person.cs | 12 -- .../Tests/ObjectPrinterAcceptanceTests.cs | 25 ++- ObjectPrinting/Tests/Person.cs | 2 + ObjectPrinting/TypePrintingConfig.cs | 33 ++++ ...er_ShouldAddCulture_ForDouble.approved.txt | 8 + ...ativeSerializer_ForPassedType.approved.txt | 8 + ...ldCorrectHandleCycleReference.approved.txt | 8 + ..._ShouldCorrectPrintDictionary.approved.txt | 19 ++ ...ieldOrProperty_WithPassedType.approved.txt | 6 + ...intObject_ShouldMatchApproved.approved.txt | 1 + ...intObject_ShouldMatchApproved.received.txt | 5 + ...Approved_DefaultConfiguration.approved.txt | 8 + ObjectPrintingTest/ObjectPrintingTest.csproj | 30 +++ ObjectPrintingTest/ObjectPrintingTests.cs | 184 ++++++++++++++++++ ...intObject_ShouldMatchApproved.received.txt | 5 + ObjectPrintingTest/TestClasses.cs | 16 ++ .../SimplePropertyMappingTests.cs | 10 +- Samples/FluentMapper/NullSourceBehavior.cs | 10 +- Samples/FluentMapper/SetterSpec.cs | 20 +- Samples/FluentMapper/TypeMappingSpec.cs | 90 ++++----- fluent-api.sln | 6 + fluent-api.sln.DotSettings | 3 + 32 files changed, 648 insertions(+), 270 deletions(-) create mode 100644 ObjectPrinting/ObjectPrintingExtension.cs create mode 100644 ObjectPrinting/PropertyPrintingConfig.cs create mode 100644 ObjectPrinting/PropertyPrintingConfigExtension.cs delete mode 100644 ObjectPrinting/Solved/ObjectExtensions.cs delete mode 100644 ObjectPrinting/Solved/ObjectPrinter.cs delete mode 100644 ObjectPrinting/Solved/PrintingConfig.cs delete mode 100644 ObjectPrinting/Solved/PropertyPrintingConfig.cs delete mode 100644 ObjectPrinting/Solved/PropertyPrintingConfigExtensions.cs delete mode 100644 ObjectPrinting/Solved/Tests/ObjectPrinterAcceptanceTests.cs delete mode 100644 ObjectPrinting/Solved/Tests/Person.cs create mode 100644 ObjectPrinting/TypePrintingConfig.cs create mode 100644 ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldAddCulture_ForDouble.approved.txt create mode 100644 ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldAlternativeSerializer_ForPassedType.approved.txt create mode 100644 ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldCorrectHandleCycleReference.approved.txt create mode 100644 ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldCorrectPrintDictionary.approved.txt create mode 100644 ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldExcludeFieldOrProperty_WithPassedType.approved.txt create mode 100644 ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.approved.txt create mode 100644 ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.received.txt create mode 100644 ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintToString_ShouldMatchApproved_DefaultConfiguration.approved.txt create mode 100644 ObjectPrintingTest/ObjectPrintingTest.csproj create mode 100644 ObjectPrintingTest/ObjectPrintingTests.cs create mode 100644 ObjectPrintingTest/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.received.txt create mode 100644 ObjectPrintingTest/TestClasses.cs diff --git a/ObjectPrinting/ObjectPrintingExtension.cs b/ObjectPrinting/ObjectPrintingExtension.cs new file mode 100644 index 00000000..cdfeec66 --- /dev/null +++ b/ObjectPrinting/ObjectPrintingExtension.cs @@ -0,0 +1,15 @@ +using System; + +namespace ObjectPrinting; + +public static class ObjectPrintingExtension +{ + public static string PrintToString(this T obj) + { + return ObjectPrinter.For().PrintToString(obj); + } + public static string PrintToString(this T obj, Func, PrintingConfig> config) + { + return config(ObjectPrinter.For()).PrintToString(); + } +} \ No newline at end of file diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index a9e08211..d4d74f23 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -1,41 +1,185 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; using System.Linq; +using System.Linq.Expressions; +using System.Reflection; using System.Text; namespace ObjectPrinting { public class PrintingConfig { - public string PrintToString(TOwner obj) + private readonly Dictionary> typeSerializers = new(); + private readonly Dictionary> propertySerializers = new(); + private readonly Dictionary propertyMaxLength = new(); + private readonly Dictionary cultureForType = new(); + private readonly Dictionary cultureForProp = new(); + private readonly HashSet excludedTypes = new(); + private readonly HashSet excludedProperties = new(); + private readonly HashSet printed = new(ReferenceEqualityComparer.Instance); + private PropertyInfo? currentProp; + + private static readonly Type[] FinalTypes = + { + typeof(int), typeof(double), typeof(float), typeof(string), + typeof(DateTime), typeof(TimeSpan) + }; + + public TypePrintingConfig ForType() + { + return new TypePrintingConfig(this, typeof(TPropType)); + } + + public PropertyPrintingConfig ForProperty( + Expression> propertySelector) + { + var propertyInfo = (PropertyInfo)((MemberExpression)propertySelector.Body).Member; + return new PropertyPrintingConfig(this, propertyInfo); + } + + public string PrintToString(TOwner? obj) { + printed.Clear(); return PrintToString(obj, 0); } - private string PrintToString(object obj, int nestingLevel) + private string PrintToString(object? obj, int nestingLevel) { - //TODO apply configurations if (obj == null) - return "null" + Environment.NewLine; - - var finalTypes = new[] + return string.Empty; + if (IsRecursion(obj)) + return "(Recursion chain)"; + return obj switch { - typeof(int), typeof(double), typeof(float), typeof(string), - typeof(DateTime), typeof(TimeSpan) + not null when IsFinalType(obj) => PrintFinalType(obj), + IDictionary dict => PrintDictionary(dict, nestingLevel), + IEnumerable list => PrintCollection(list, nestingLevel), + _ => PrintComplexObject(obj, nestingLevel) }; - if (finalTypes.Contains(obj.GetType())) - return obj + Environment.NewLine; + } + + private string PrintFinalType(object obj) + { + var type = obj.GetType(); + var result = (obj switch + { + IFormattable f when currentProp != null && cultureForProp.TryGetValue(currentProp, out var culture) => + f.ToString(null, culture), + IFormattable f when cultureForType.ContainsKey(type) => f.ToString(null, cultureForType[type]), + _ => obj.ToString() + })!; + + if (currentProp != null && propertyMaxLength.TryGetValue(currentProp, out var length)) + result = result.Length > length ? result[..length] : result; - var identation = new string('\t', nestingLevel + 1); + return result; + } + + private bool IsRecursion(object obj) + { + if (printed.Contains(obj)) + return true; + printed.Add(obj); + return false; + } + + private static bool IsFinalType(object obj) => FinalTypes.Contains(obj.GetType()); + + private string PrintComplexObject(object obj, int nestingLevel) + { var sb = new StringBuilder(); var type = obj.GetType(); sb.AppendLine(type.Name); - foreach (var propertyInfo in type.GetProperties()) + + foreach (var property in type.GetProperties()) { - sb.Append(identation + propertyInfo.Name + " = " + - PrintToString(propertyInfo.GetValue(obj), - nestingLevel + 1)); + currentProp = property; + if (excludedTypes.Contains(property.PropertyType) || excludedProperties.Contains(property)) + continue; + var serializedValue = Serialize(property, obj, nestingLevel + 1); + sb.Append('\t', nestingLevel + 1); + sb.AppendLine($"{property.Name} = {serializedValue}"); } + + currentProp = null; + printed.Add(obj); + return sb.ToString(); + } + + private string PrintCollection(IEnumerable collection, int nestingLevel) + { + var sb = new StringBuilder(); + foreach (var item in collection) + sb.Append(PrintToString(item, nestingLevel)); return sb.ToString(); } + + private string PrintDictionary(IDictionary dictionary, int nestingLevel) + { + var sb = new StringBuilder(); + sb.Append('\t', nestingLevel); + sb.AppendLine(dictionary.GetType().Name); + foreach (DictionaryEntry entry in dictionary) + { + var key = entry.Key; + var value = entry.Value; + sb.Append('\t', nestingLevel + 1); + sb.AppendLine($"{key.PrintToString()} = {value.PrintToString()}"); + } + + return sb.ToString(); + } + + private string Serialize(PropertyInfo property, object parent, int nestingLevel) + { + var value = property.GetValue(parent); + if (value == null) + return "null"; + + if (propertySerializers.TryGetValue(property, out var propertySerializer)) + return propertySerializer(value); + if (typeSerializers.TryGetValue(property.PropertyType, out var typeSerializer)) + return typeSerializer(value); + + return PrintToString(value, nestingLevel); + } + + public void AddTypeSerializer(Func print) + { + var type = typeof(TPropType); + typeSerializers[type] = print; + } + + public void AddPropertySerializer(PropertyInfo propertyInfo, Func print) + { + propertySerializers[propertyInfo] = print; + } + + public void AddExcludedProperty(PropertyInfo propertyInfo) + { + excludedProperties.Add(propertyInfo); + } + + public void AddExcludedType(Type type) + { + excludedTypes.Add(type); + } + + public void AddTypeCulture(CultureInfo cultureInfo) + { + cultureForType.Add(typeof(TType), cultureInfo); + } + + public void AddPropertyCulture(PropertyInfo propertyInfo, CultureInfo cultureInfo) + { + cultureForProp.Add(propertyInfo, cultureInfo); + } + + public void AddPropertyMaxLenght(PropertyInfo propertyInfo, int maxLength) + { + propertyMaxLength.Add(propertyInfo, maxLength); + } } } \ No newline at end of file diff --git a/ObjectPrinting/PropertyPrintingConfig.cs b/ObjectPrinting/PropertyPrintingConfig.cs new file mode 100644 index 00000000..8fade4ad --- /dev/null +++ b/ObjectPrinting/PropertyPrintingConfig.cs @@ -0,0 +1,30 @@ +using System; +using System.Globalization; +using System.Reflection; +using ObjectPrinting; + +public class PropertyPrintingConfig( + PrintingConfig parentConfig, + PropertyInfo propertyInfo) +{ + public readonly PrintingConfig parentConfig = parentConfig; + public readonly PropertyInfo propertyInfo = propertyInfo; + + public PrintingConfig Using(Func print) + { + parentConfig.AddPropertySerializer(propertyInfo, obj => print((TPropType)obj)); + return parentConfig; + } + + public PrintingConfig WithCulture(CultureInfo culture) + { + parentConfig.AddPropertyCulture(propertyInfo, culture); + return parentConfig; + } + + public PrintingConfig Exclude() + { + parentConfig.AddExcludedProperty(propertyInfo); + return parentConfig; + } +} \ No newline at end of file diff --git a/ObjectPrinting/PropertyPrintingConfigExtension.cs b/ObjectPrinting/PropertyPrintingConfigExtension.cs new file mode 100644 index 00000000..150cd0d6 --- /dev/null +++ b/ObjectPrinting/PropertyPrintingConfigExtension.cs @@ -0,0 +1,18 @@ +using System; + +namespace ObjectPrinting; + +public static class PropertyPrintingConfigExtension +{ + public static PrintingConfig TrimTo(this PropertyPrintingConfig config, + int maxLength) + { + if (maxLength < 1) + throw new ArgumentException($"{nameof(maxLength)} should be greater than 1"); + + var parentConfig = config.parentConfig; + + parentConfig.AddPropertyMaxLenght(config.propertyInfo, maxLength); + return parentConfig; + } +} \ No newline at end of file diff --git a/ObjectPrinting/Solved/ObjectExtensions.cs b/ObjectPrinting/Solved/ObjectExtensions.cs deleted file mode 100644 index b0c94553..00000000 --- a/ObjectPrinting/Solved/ObjectExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ObjectPrinting.Solved -{ - public static class ObjectExtensions - { - public static string PrintToString(this T obj) - { - return ObjectPrinter.For().PrintToString(obj); - } - } -} \ No newline at end of file diff --git a/ObjectPrinting/Solved/ObjectPrinter.cs b/ObjectPrinting/Solved/ObjectPrinter.cs deleted file mode 100644 index 540ee769..00000000 --- a/ObjectPrinting/Solved/ObjectPrinter.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ObjectPrinting.Solved -{ - public class ObjectPrinter - { - public static PrintingConfig For() - { - return new PrintingConfig(); - } - } -} \ No newline at end of file diff --git a/ObjectPrinting/Solved/PrintingConfig.cs b/ObjectPrinting/Solved/PrintingConfig.cs deleted file mode 100644 index 0ec5aeb2..00000000 --- a/ObjectPrinting/Solved/PrintingConfig.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Text; - -namespace ObjectPrinting.Solved -{ - public class PrintingConfig - { - public PropertyPrintingConfig Printing() - { - return new PropertyPrintingConfig(this); - } - - public PropertyPrintingConfig Printing(Expression> memberSelector) - { - return new PropertyPrintingConfig(this); - } - - public PrintingConfig Excluding(Expression> memberSelector) - { - return this; - } - - internal PrintingConfig Excluding() - { - return this; - } - - 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(); - } - } -} \ No newline at end of file diff --git a/ObjectPrinting/Solved/PropertyPrintingConfig.cs b/ObjectPrinting/Solved/PropertyPrintingConfig.cs deleted file mode 100644 index a509697d..00000000 --- a/ObjectPrinting/Solved/PropertyPrintingConfig.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Globalization; - -namespace ObjectPrinting.Solved -{ - public class PropertyPrintingConfig : IPropertyPrintingConfig - { - private readonly PrintingConfig printingConfig; - - public PropertyPrintingConfig(PrintingConfig printingConfig) - { - this.printingConfig = printingConfig; - } - - public PrintingConfig Using(Func print) - { - return printingConfig; - } - - public PrintingConfig Using(CultureInfo culture) - { - return printingConfig; - } - - PrintingConfig IPropertyPrintingConfig.ParentConfig => printingConfig; - } - - public interface IPropertyPrintingConfig - { - PrintingConfig ParentConfig { get; } - } -} \ No newline at end of file diff --git a/ObjectPrinting/Solved/PropertyPrintingConfigExtensions.cs b/ObjectPrinting/Solved/PropertyPrintingConfigExtensions.cs deleted file mode 100644 index dd392239..00000000 --- a/ObjectPrinting/Solved/PropertyPrintingConfigExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace ObjectPrinting.Solved -{ - public static class PropertyPrintingConfigExtensions - { - public static string PrintToString(this T obj, Func, PrintingConfig> config) - { - return config(ObjectPrinter.For()).PrintToString(obj); - } - - public static PrintingConfig TrimmedToLength(this PropertyPrintingConfig propConfig, int maxLen) - { - return ((IPropertyPrintingConfig)propConfig).ParentConfig; - } - - } -} \ No newline at end of file diff --git a/ObjectPrinting/Solved/Tests/ObjectPrinterAcceptanceTests.cs b/ObjectPrinting/Solved/Tests/ObjectPrinterAcceptanceTests.cs deleted file mode 100644 index ac52d5ee..00000000 --- a/ObjectPrinting/Solved/Tests/ObjectPrinterAcceptanceTests.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Globalization; -using NUnit.Framework; - -namespace ObjectPrinting.Solved.Tests -{ - [TestFixture] - public class ObjectPrinterAcceptanceTests - { - [Test] - public void Demo() - { - var person = new Person { Name = "Alex", Age = 19 }; - - var printer = ObjectPrinter.For() - //1. Исключить из сериализации свойства определенного типа - .Excluding() - //2. Указать альтернативный способ сериализации для определенного типа - .Printing().Using(i => i.ToString("X")) - //3. Для числовых типов указать культуру - .Printing().Using(CultureInfo.InvariantCulture) - //4. Настроить сериализацию конкретного свойства - //5. Настроить обрезание строковых свойств (метод должен быть виден только для строковых свойств) - .Printing(p => p.Name).TrimmedToLength(10) - //6. Исключить из сериализации конкретного свойства - .Excluding(p => p.Age); - - string s1 = printer.PrintToString(person); - - //7. Синтаксический сахар в виде метода расширения, сериализующего по-умолчанию - string s2 = person.PrintToString(); - - //8. ...с конфигурированием - string s3 = person.PrintToString(s => s.Excluding(p => p.Age)); - Console.WriteLine(s1); - Console.WriteLine(s2); - Console.WriteLine(s3); - } - } -} \ No newline at end of file diff --git a/ObjectPrinting/Solved/Tests/Person.cs b/ObjectPrinting/Solved/Tests/Person.cs deleted file mode 100644 index 858ebbf8..00000000 --- a/ObjectPrinting/Solved/Tests/Person.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace ObjectPrinting.Solved.Tests -{ - public class Person - { - public Guid Id { get; set; } - public string Name { get; set; } - public double Height { get; set; } - public int Age { get; set; } - } -} \ No newline at end of file diff --git a/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs b/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs index 4c8b2445..fd024b5b 100644 --- a/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs @@ -1,4 +1,6 @@ -using NUnit.Framework; +using System; +using System.Globalization; +using NUnit.Framework; namespace ObjectPrinting.Tests { @@ -8,20 +10,31 @@ public class ObjectPrinterAcceptanceTests [Test] public void Demo() { - var person = new Person { Name = "Alex", Age = 19 }; + var person = new Person { Name = "Alex_ShouldntSeeIt", Age = 19, Surname = "Bronson" ,Height = 12.4}; + person.Parent = person; + - var printer = ObjectPrinter.For(); + var printer = ObjectPrinter.For() //1. Исключить из сериализации свойства определенного типа + .ForType().Exclude() //2. Указать альтернативный способ сериализации для определенного типа + .ForType().Using(i => i.ToString()) //3. Для числовых типов указать культуру + .ForType().WithCulture(CultureInfo.InvariantCulture) //4. Настроить сериализацию конкретного свойства + .ForProperty(p => p.Name).TrimTo(4) //5. Настроить обрезание строковых свойств (метод должен быть виден только для строковых свойств) + .ForProperty(p => p.Surname).Using(s =>s.ToUpper() ) //6. Исключить из сериализации конкретного свойства - - string s1 = printer.PrintToString(person); + .ForProperty(p => p.Age).Exclude(); - //7. Синтаксический сахар в виде метода расширения, сериализующего по-умолчанию + + string s1 = printer.PrintToString(person); + Console.WriteLine(s1); + //7. Синтаксический сахар в виде метода расширения, сериализующего по-умолчанию + var s2 = person.PrintToString(); //8. ...с конфигурированием + var s3 = person.PrintToString(config =>config.ForType().Exclude() ); } } } \ No newline at end of file diff --git a/ObjectPrinting/Tests/Person.cs b/ObjectPrinting/Tests/Person.cs index f9555955..c3673a8a 100644 --- a/ObjectPrinting/Tests/Person.cs +++ b/ObjectPrinting/Tests/Person.cs @@ -6,7 +6,9 @@ public class Person { public Guid Id { get; set; } public string Name { get; set; } + public string Surname { get; set; } public double Height { get; set; } public int Age { get; set; } + public Person Parent { get; set; } } } \ No newline at end of file diff --git a/ObjectPrinting/TypePrintingConfig.cs b/ObjectPrinting/TypePrintingConfig.cs new file mode 100644 index 00000000..14664fce --- /dev/null +++ b/ObjectPrinting/TypePrintingConfig.cs @@ -0,0 +1,33 @@ +using System; +using System.Globalization; +using ObjectPrinting; + +public class TypePrintingConfig +{ + private readonly PrintingConfig parentConfig; + private readonly Type type; + + public TypePrintingConfig(PrintingConfig parentConfig, Type type) + { + this.parentConfig = parentConfig; + this.type = type; + } + + public PrintingConfig Using(Func print) + { + parentConfig.AddTypeSerializer(obj => print((TPropType)obj)); + return parentConfig; + } + + public PrintingConfig WithCulture(CultureInfo culture) + { + parentConfig.AddTypeCulture(culture); + return parentConfig; + } + + public PrintingConfig Exclude() + { + parentConfig.AddExcludedType(type); + return parentConfig; + } +} \ No newline at end of file diff --git a/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldAddCulture_ForDouble.approved.txt b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldAddCulture_ForDouble.approved.txt new file mode 100644 index 00000000..1d48058d --- /dev/null +++ b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldAddCulture_ForDouble.approved.txt @@ -0,0 +1,8 @@ +Person + Name = Alex + Surname = White + Age = 19 + Height = 199.9 + BirthDate = 01.01.0001 0:00:00 + Address = null + Parent = null diff --git a/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldAlternativeSerializer_ForPassedType.approved.txt b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldAlternativeSerializer_ForPassedType.approved.txt new file mode 100644 index 00000000..83bc4dfb --- /dev/null +++ b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldAlternativeSerializer_ForPassedType.approved.txt @@ -0,0 +1,8 @@ +Person + Name = String field: Alex + Surname = String field: White + Age = Int field: 19 + Height = 0 + BirthDate = 21.01.2021 0:00:00 + Address = null + Parent = null diff --git a/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldCorrectHandleCycleReference.approved.txt b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldCorrectHandleCycleReference.approved.txt new file mode 100644 index 00000000..864c46fa --- /dev/null +++ b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldCorrectHandleCycleReference.approved.txt @@ -0,0 +1,8 @@ +Person + Name = null + Surname = null + Age = 0 + Height = 0 + BirthDate = 01.01.0001 0:00:00 + Address = null + Parent = (Recursion chain) diff --git a/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldCorrectPrintDictionary.approved.txt b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldCorrectPrintDictionary.approved.txt new file mode 100644 index 00000000..b8389fd1 --- /dev/null +++ b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldCorrectPrintDictionary.approved.txt @@ -0,0 +1,19 @@ +Dictionary`2 + person1 = Person + Name = Mary + Surname = null + Age = 0 + Height = 0 + BirthDate = 01.01.0001 0:00:00 + Address = null + Parent = null + + person2 = Person + Name = Alice + Surname = null + Age = 0 + Height = 0 + BirthDate = 01.01.0001 0:00:00 + Address = null + Parent = null + diff --git a/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldExcludeFieldOrProperty_WithPassedType.approved.txt b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldExcludeFieldOrProperty_WithPassedType.approved.txt new file mode 100644 index 00000000..2ddb60f6 --- /dev/null +++ b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.ObjectPrinter_ShouldExcludeFieldOrProperty_WithPassedType.approved.txt @@ -0,0 +1,6 @@ +Person + Age = 19 + Height = 0 + BirthDate = 21.01.2021 0:00:00 + Address = null + Parent = null diff --git a/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.approved.txt b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.approved.txt new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.approved.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.received.txt b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.received.txt new file mode 100644 index 00000000..4d49a0ac --- /dev/null +++ b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.received.txt @@ -0,0 +1,5 @@ +Person + Name = John + Age = 30 + BirthDate = 01.01.1991 0:00:00 + Address = null diff --git a/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintToString_ShouldMatchApproved_DefaultConfiguration.approved.txt b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintToString_ShouldMatchApproved_DefaultConfiguration.approved.txt new file mode 100644 index 00000000..907f6987 --- /dev/null +++ b/ObjectPrintingTest/ApprovalFiles/ObjectPrinting_Tests.PrintToString_ShouldMatchApproved_DefaultConfiguration.approved.txt @@ -0,0 +1,8 @@ +Person + Name = Alex + Surname = null + Age = 19 + Height = 0 + BirthDate = 21.01.2021 0:00:00 + Address = null + Parent = null diff --git a/ObjectPrintingTest/ObjectPrintingTest.csproj b/ObjectPrintingTest/ObjectPrintingTest.csproj new file mode 100644 index 00000000..d6902be8 --- /dev/null +++ b/ObjectPrintingTest/ObjectPrintingTest.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + diff --git a/ObjectPrintingTest/ObjectPrintingTests.cs b/ObjectPrintingTest/ObjectPrintingTests.cs new file mode 100644 index 00000000..21312976 --- /dev/null +++ b/ObjectPrintingTest/ObjectPrintingTests.cs @@ -0,0 +1,184 @@ +using System.Globalization; +using ApprovalTests; +using ApprovalTests.Namers; +using ApprovalTests.Reporters; +using FluentAssertions; +using NUnit.Framework; +using ObjectPrinting; + +namespace ObjectPrintingTest +{ + [TestFixture] + [UseReporter(typeof(DiffReporter))] + [UseApprovalSubdirectory("ApprovalFiles")] + public class ObjectPrinting_Tests + { + [Test] + public void PrintToString_ShouldMatchApproved_DefaultConfiguration() + { + var person = new Person { Name = "Alex", Age = 19, BirthDate = new DateTime(2021, 1, 21) }; + + var printer = ObjectPrinter.For(); + var result = printer.PrintToString(person); + + Approvals.Verify(result); + } + + [Test] + public void ObjectPrinter_ShouldExcludeFieldOrProperty_WithPassedType() + { + var person = new Person { Name = "Alex", Age = 19, BirthDate = new DateTime(2021, 1, 21) }; + + var printer = ObjectPrinter + .For() + .ForType() + .Exclude(); + + + Approvals.Verify(printer.PrintToString(person)); + } + + [Test] + public void ObjectPrinter_ShouldAlternativeSerializer_ForPassedType() + { + var person = new Person + { Name = "Alex", Surname = "White", Age = 19, BirthDate = new DateTime(2021, 1, 21) }; + + var printer = ObjectPrinter + .For() + .ForType().Using(s => $"String field: {s}") + .ForType().Using(n => $"Int field: {n}"); + + + Approvals.Verify(printer.PrintToString(person)); + } + + [Test] + public void ObjectPrinter_ShouldAddCulture_ForDouble() + { + var person = new Person { Name = "Alex", Surname = "White", Age = 19, Height = 199.9 }; + + var printer = ObjectPrinter.For() + .ForProperty(p => p.Height) + .WithCulture(new CultureInfo("en-US")); + + + Approvals.Verify(printer.PrintToString(person)); + } + + [Test] + public void ObjectPrinter_ShouldAddCulture_ForDateTime() + { + var person = new Person + { Name = "Alex", Surname = "White", Age = 19, BirthDate = new DateTime(2021, 1, 21) }; + + var printer = ObjectPrinter.For() + .ForProperty(p => p.BirthDate) + .WithCulture(CultureInfo.GetCultureInfo("en-US")); + + Approvals.Verify(printer.PrintToString(person)); + } + + [Test] + public void ObjectPrinter_ShouldAlternativeSerializer_ForSpecificPropertyOrField() + { + var person = new Person + { Name = "Alex", Surname = "White", Age = 19, BirthDate = new DateTime(2021, 1, 21) }; + + var printer = ObjectPrinter.For() + .ForProperty(p => p.Name).Using(name => $"My name is {name}") + .ForProperty(p => p.BirthDate).Using(date => date.ToString("M.dd")); + + Approvals.Verify(printer.PrintToString(person)); + } + + [Test] + public void ObjectPrinter_ShouldTruncateSerializer_ForString() + { + var person = new Person + { Name = "Alex", Surname = "White", Age = 19, BirthDate = new DateTime(2021, 1, 21) }; + + var printer = ObjectPrinter.For() + .ForProperty(obj => obj.Name).TrimTo(2); + + Approvals.Verify(printer.PrintToString(person)); + } + + [Test] + public void ObjectPrinter_ShouldExclude_SpecificProperty() + { + var person = new Person + { Name = "Alex", Surname = "White", Age = 19, BirthDate = new DateTime(2021, 1, 21) }; + + var printer = ObjectPrinter.For() + .ForProperty(p => p.Name).Exclude(); + + + Approvals.Verify(printer.PrintToString(person)); + } + + [Test] + public void ObjectPrinter_ShouldPrintField_ForInnerClass() + { + var person = new Person + { + Name = "Alex", + Surname = "White", + Age = 19, + BirthDate = new DateTime(2021, 1, 21), + Parent = new Person { Name = "Sam" } + }; + + var printer = ObjectPrinter.For(); + + Approvals.Verify(printer.PrintToString(person)); + } + + [Test] + public void ObjectPrinter_ShouldCorrectPrintArray() + { + var list = new[] { new Person { Name = "Mary" }, new Person { Name = "Alice" } }; + + var printer = ObjectPrinter.For(); + + Approvals.Verify(printer.PrintToString(list)); + } + + [Test] + public void ObjectPrinter_ShouldCorrectPrintList() + { + var list = new List { new Person { Name = "Mary" }, new Person { Name = "Alice" } }; + + var printer = ObjectPrinter.For>(); + + Approvals.Verify(printer.PrintToString(list)); + } + + [Test] + public void ObjectPrinter_ShouldCorrectPrintDictionary() + { + var list = new Dictionary + { + { "person1", new Person { Name = "Mary" } }, + { "person2", new Person { Name = "Alice" } } + }; + + var printer = ObjectPrinter.For>(); + + Approvals.Verify(printer.PrintToString(list)); + } + + [Test] //7 + public void ObjectPrinter_ShouldCorrectHandleCycleReference() + { + var a = new Person() { }; + a.Parent = a; + + var printer = ObjectPrinter.For(); + Func act = () => printer.PrintToString(a); + + act.Should().NotThrow(); + Approvals.Verify(printer.PrintToString(a)); + } + } +} \ No newline at end of file diff --git a/ObjectPrintingTest/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.received.txt b/ObjectPrintingTest/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.received.txt new file mode 100644 index 00000000..4d49a0ac --- /dev/null +++ b/ObjectPrintingTest/ObjectPrinting_Tests.PrintObject_ShouldMatchApproved.received.txt @@ -0,0 +1,5 @@ +Person + Name = John + Age = 30 + BirthDate = 01.01.1991 0:00:00 + Address = null diff --git a/ObjectPrintingTest/TestClasses.cs b/ObjectPrintingTest/TestClasses.cs new file mode 100644 index 00000000..6ddb6fda --- /dev/null +++ b/ObjectPrintingTest/TestClasses.cs @@ -0,0 +1,16 @@ +public class Person +{ + public string Name { get; set; } + public string Surname { get; set; } + public int Age { get; set; } + public double Height { get; set; } + public DateTime BirthDate { get; set; } + public Address Address { get; set; } + public Person Parent { get; set; } +} + +public class Address +{ + public string Street { get; set; } + public string City { get; set; } +} \ No newline at end of file diff --git a/Samples/FluentMapper.Tests/SimplePropertyMappingTests.cs b/Samples/FluentMapper.Tests/SimplePropertyMappingTests.cs index 513877a4..546309b3 100644 --- a/Samples/FluentMapper.Tests/SimplePropertyMappingTests.cs +++ b/Samples/FluentMapper.Tests/SimplePropertyMappingTests.cs @@ -28,11 +28,11 @@ public void PropertyMatching() var mapper = FluentMapper.ThatMaps() .From() .ThatSets(tgt => tgt.Str).From(src => src.Name) - .ThatSets(tgt => tgt.Num).From(src => src.ID) + .ThatSets(tgt => tgt.Num).From(src => src.Id) .Create(); var source = new Source { - ID = 7, + Id = 7, Name = "Bob" }; @@ -49,12 +49,12 @@ public void IgnoringProperties() .From() .ThatSets(tgt => tgt.Str).From(src => src.Name) .IgnoringTargetProperty(tgt => tgt.Num) - .IgnoringSourceProperty(src => src.ID) + .IgnoringSourceProperty(src => src.Id) .Create(); var source = new Source { - ID = 7, + Id = 7, Name = "Bob" }; @@ -98,7 +98,7 @@ public sealed class Target public sealed class Source { public string Name { get; set; } - public int ID { get; set; } + public int Id { get; set; } } } } diff --git a/Samples/FluentMapper/NullSourceBehavior.cs b/Samples/FluentMapper/NullSourceBehavior.cs index d859712a..c2c485c4 100644 --- a/Samples/FluentMapper/NullSourceBehavior.cs +++ b/Samples/FluentMapper/NullSourceBehavior.cs @@ -10,24 +10,24 @@ public interface INullSourceBehaviorState public sealed class NullSourceBehavior : INullSourceBehaviorState { - TypeMappingSpec INullSourceBehaviorState.Spec => _spec; + TypeMappingSpec INullSourceBehaviorState.Spec => spec; - private TypeMappingSpec _spec; + private TypeMappingSpec spec; public NullSourceBehavior(TypeMappingSpec spec) { - _spec = spec; + this.spec = spec; } public TypeMappingSpec ReturnNull() { - return _spec.Transforms() + return spec.Transforms() .WithAssembler(new ReturnNullAssembler()); } public TypeMappingSpec CreateEmpty() { - return _spec.Transforms() + return spec.Transforms() .WithAssembler(new CreateEmptyAssembler()); } } diff --git a/Samples/FluentMapper/SetterSpec.cs b/Samples/FluentMapper/SetterSpec.cs index 0cd7ac48..d61e092a 100644 --- a/Samples/FluentMapper/SetterSpec.cs +++ b/Samples/FluentMapper/SetterSpec.cs @@ -15,16 +15,16 @@ public interface ISetterSpecProperties public sealed class SetterSpec : ISetterSpecProperties { - private TypeMappingSpec _spec; - private PropertyInfo _targetProperty; + private TypeMappingSpec spec; + private PropertyInfo targetProperty; public SetterSpec( TypeMappingSpec spec, PropertyInfo targetProperty ) { - _spec = spec; - _targetProperty = targetProperty; + this.spec = spec; + this.targetProperty = targetProperty; } public TypeMappingSpec From(Expression> propertyExpression) @@ -32,15 +32,15 @@ public TypeMappingSpec From(Expression>(tgtSetterExpr, tgtParam, srcParam) .Compile(); - var specProperties = _spec.Properties(); + var specProperties = spec.Properties(); - return _spec + return spec .Transforms().WithMappingActions( specProperties.MappingActions .Concat(new[] { setterAction }) @@ -53,14 +53,14 @@ public TypeMappingSpec From(Expression x != _targetProperty) + .Where(x => x != targetProperty) .ToArray() ) ; } - TypeMappingSpec ISetterSpecProperties.Spec => _spec; + TypeMappingSpec ISetterSpecProperties.Spec => spec; - PropertyInfo ISetterSpecProperties.TargetProperty => _targetProperty; + PropertyInfo ISetterSpecProperties.TargetProperty => targetProperty; } } \ No newline at end of file diff --git a/Samples/FluentMapper/TypeMappingSpec.cs b/Samples/FluentMapper/TypeMappingSpec.cs index d2e25545..7631a1da 100644 --- a/Samples/FluentMapper/TypeMappingSpec.cs +++ b/Samples/FluentMapper/TypeMappingSpec.cs @@ -10,10 +10,10 @@ public sealed class TypeMappingSpec : ITypeMappingSpecProperties, ITypeMappingSpecTransforms { - private readonly IEnumerable> _mappingActions; - private readonly IEnumerable _srcProperties; - private readonly IEnumerable _tgtProperties; - private readonly IAssembler _assembler; + private readonly IEnumerable> mappingActions; + private readonly IEnumerable srcProperties; + private readonly IEnumerable tgtProperties; + private readonly IAssembler assembler; public TypeMappingSpec() : this( @@ -31,10 +31,10 @@ private TypeMappingSpec( IAssembler assembler ) { - _mappingActions = mappingActions; - _tgtProperties = targetProperties; - _srcProperties = sourceProperties; - _assembler = assembler; + this.mappingActions = mappingActions; + tgtProperties = targetProperties; + srcProperties = sourceProperties; + this.assembler = assembler; } public NullSourceBehavior WithNullSource() @@ -42,19 +42,19 @@ public NullSourceBehavior WithNullSource() return new NullSourceBehavior(this); } - IEnumerable ITypeMappingSpecProperties.SourceProperties => _srcProperties; - IEnumerable ITypeMappingSpecProperties.TargetProperties => _tgtProperties; - IEnumerable> ITypeMappingSpecProperties.MappingActions => _mappingActions; - IAssembler ITypeMappingSpecProperties.Assembler => _assembler; + IEnumerable ITypeMappingSpecProperties.SourceProperties => srcProperties; + IEnumerable ITypeMappingSpecProperties.TargetProperties => tgtProperties; + IEnumerable> ITypeMappingSpecProperties.MappingActions => mappingActions; + IAssembler ITypeMappingSpecProperties.Assembler => assembler; TypeMappingSpec ITypeMappingSpecTransforms .WithSourceProperties(IEnumerable sourceProperties) { return new TypeMappingSpec( - _tgtProperties, + tgtProperties, sourceProperties, - _mappingActions, - _assembler + mappingActions, + assembler ); } @@ -63,9 +63,9 @@ TypeMappingSpec ITypeMappingSpecTransforms { return new TypeMappingSpec( targetProperties, - _srcProperties, - _mappingActions, - _assembler + srcProperties, + mappingActions, + assembler ); } @@ -73,10 +73,10 @@ TypeMappingSpec ITypeMappingSpecTransforms .WithMappingActions(IEnumerable> mappingActions) { return new TypeMappingSpec( - _tgtProperties, - _srcProperties, + tgtProperties, + srcProperties, mappingActions, - _assembler + assembler ); } @@ -84,21 +84,21 @@ TypeMappingSpec ITypeMappingSpecTransforms .WithAssembler(IAssembler assembler) { return new TypeMappingSpec( - _tgtProperties, - _srcProperties, - _mappingActions, + tgtProperties, + srcProperties, + mappingActions, assembler ); } public IMapper Create() { - var unmappedTargets = _tgtProperties - .Where(tgtProp => !_srcProperties + var unmappedTargets = tgtProperties + .Where(tgtProp => !srcProperties .Any(srcProp => srcProp.Name == tgtProp.Name) ); - var unmappedSources = _srcProperties - .Where(srcProp => !_tgtProperties + var unmappedSources = srcProperties + .Where(srcProp => !tgtProperties .Any(tgtProp => tgtProp.Name == srcProp.Name) ); @@ -120,9 +120,9 @@ public IMapper Create() var actions = new List(); - foreach (var targetProperty in _tgtProperties) + foreach (var targetProperty in tgtProperties) { - var sourceProperty = _srcProperties + var sourceProperty = srcProperties .FirstOrDefault(x => x.Name == targetProperty.Name); if (sourceProperty == null) @@ -135,7 +135,7 @@ public IMapper Create() actions.Add(setterCallExpression); } - actions.AddRange(_mappingActions + actions.AddRange(mappingActions .Select(ToExpression) .Select(x => Expression.Invoke(x, tgtParam, srcParam)) ); @@ -150,7 +150,7 @@ public IMapper Create() .Compile() ; - return new Mapper(compiledAction, _assembler); + return new Mapper(compiledAction, assembler); } public SetterSpec ThatSets( @@ -167,13 +167,13 @@ public TypeMappingSpec { var propInfo = GetPropertyInfo(propertyExpression, nameof(IgnoringTargetProperty), "tgt"); - var targetProperties = this._tgtProperties.Where(x => !x.Equals(propInfo)); + var targetProperties = this.tgtProperties.Where(x => !x.Equals(propInfo)); return new TypeMappingSpec( targetProperties.ToArray(), - _srcProperties, - _mappingActions, - _assembler + srcProperties, + mappingActions, + assembler ); } @@ -181,13 +181,13 @@ public TypeMappingSpec IgnoringSourceProperty(Expression !x.Equals(propInfo)); + var sourceProperties = this.srcProperties.Where(x => !x.Equals(propInfo)); return new TypeMappingSpec( - _tgtProperties, + tgtProperties, sourceProperties.ToArray(), - _mappingActions, - _assembler + mappingActions, + assembler ); } @@ -215,18 +215,18 @@ private Expression> ToExpression(Action delegateI private sealed class Mapper : IMapper { - private readonly Action _mappingAction; - private readonly IAssembler _assembler; + private readonly Action mappingAction; + private readonly IAssembler assembler; public Mapper(Action mappingAction, IAssembler assembler) { - _mappingAction = mappingAction; - _assembler = assembler; + this.mappingAction = mappingAction; + this.assembler = assembler; } public TTgt Map(TSrc source) { - return _assembler.Assemble(source, _mappingAction); + return assembler.Assemble(source, mappingAction); } } } diff --git a/fluent-api.sln b/fluent-api.sln index 69c8db9e..50819c9a 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", "{BA8AA1F4-1EBB-421B-B408-3D6EC3CA2ECC}" +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 + {BA8AA1F4-1EBB-421B-B408-3D6EC3CA2ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA8AA1F4-1EBB-421B-B408-3D6EC3CA2ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA8AA1F4-1EBB-421B-B408-3D6EC3CA2ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA8AA1F4-1EBB-421B-B408-3D6EC3CA2ECC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/fluent-api.sln.DotSettings b/fluent-api.sln.DotSettings index 135b83ec..53fe49b2 100644 --- a/fluent-api.sln.DotSettings +++ b/fluent-api.sln.DotSettings @@ -1,6 +1,9 @@  <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /></Policy> + True True True Imported 10.10.2016