From c74de348c98db748972112dd04890f8452b2e8aa Mon Sep 17 00:00:00 2001 From: Yevhen Cherkes Date: Sun, 10 Dec 2023 15:42:01 +0200 Subject: [PATCH] Add Frozen Collections (NET80) (#17) * Add Frozen Collections (NET80) * remove editorconfig * unify code --- README.md | 2 +- VarDump.sln | 2 +- src/CSharpDumper.cs | 5 ++ src/Utils/ReflectionUtils.cs | 20 ++++- src/VarDump.csproj | 6 +- src/Visitor/KnownTypes/CollectionVisitor.cs | 14 +-- src/Visitor/KnownTypes/DictionaryVisitor.cs | 12 +-- src/VisualBasicDumper.cs | 5 ++ test/UnitTests/DataTableSpec.cs | 6 +- test/UnitTests/FrozenCollectionsNet8Spec.cs | 97 +++++++++++++++++++++ test/UnitTests/UnitTests.csproj | 2 +- 11 files changed, 149 insertions(+), 22 deletions(-) create mode 100644 test/UnitTests/FrozenCollectionsNet8Spec.cs diff --git a/README.md b/README.md index 0b04554..06c8fbf 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ VarDump is a utility for serialization runtime objects to C# or Visual Basic str Developed as a free alternative of [ObjectDumper.NET](https://github.com/thomasgalliker/ObjectDumper), which is not free for commercial use. -[![nuget version](https://img.shields.io/badge/Nuget-v0.2.7-blue)](https://www.nuget.org/packages/VarDump) +[![nuget version](https://img.shields.io/badge/Nuget-v0.2.8-blue)](https://www.nuget.org/packages/VarDump) [![nuget downloads](https://img.shields.io/nuget/dt/VarDump?label=Downloads)](https://www.nuget.org/packages/VarDump) # Powered By diff --git a/VarDump.sln b/VarDump.sln index 52fee07..8cb9c97 100644 --- a/VarDump.sln +++ b/VarDump.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 17.4.33213.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VarDump", "src\VarDump.csproj", "{ED778772-EC95-4362-8C3C-C2DFF8F0ABD6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "test\UnitTests\UnitTests.csproj", "{6CDE3AAC-4726-438B-8D09-51ED6434BF68}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "test\UnitTests\UnitTests.csproj", "{6CDE3AAC-4726-438B-8D09-51ED6434BF68}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/CSharpDumper.cs b/src/CSharpDumper.cs index 868b108..a600a8b 100644 --- a/src/CSharpDumper.cs +++ b/src/CSharpDumper.cs @@ -36,6 +36,11 @@ public string Dump(object obj) public void Dump(object obj, TextWriter textWriter) { + if (textWriter == null) + { + throw new ArgumentNullException(nameof(textWriter)); + } + DumpImpl(obj, textWriter); } diff --git a/src/Utils/ReflectionUtils.cs b/src/Utils/ReflectionUtils.cs index 641b8ce..df54bf9 100644 --- a/src/Utils/ReflectionUtils.cs +++ b/src/Utils/ReflectionUtils.cs @@ -229,11 +229,27 @@ public static bool IsGenericCollection(this Type type) return hasICollection; } - public static bool IsPublicImmutableCollection(this Type type) + public static bool IsPublicImmutableOrFrozenCollection(this Type type) { var typeFullName = type.FullName ?? ""; - return type.IsPublic && typeFullName.StartsWith("System.Collections.Immutable"); + return type.IsPublic && typeFullName.StartsWith("System.Collections.Immutable") || IsFrozenCollection(typeFullName); + } + + private static bool IsFrozenCollection(string typeFullName) + { + return typeFullName.StartsWith("System.Collections.Frozen"); + } + + public static string GetImmutableOrFrozenTypeName(this Type type) + { + var typeFullName = type.FullName; + var typeName = type.Name; + if (IsFrozenCollection(typeFullName)) + { + typeName = typeName.Substring(typeName.IndexOf("Frozen", StringComparison.Ordinal)); + } + return typeName.Split('`')[0]; } public static bool IsReadonlyCollection(this Type type) diff --git a/src/VarDump.csproj b/src/VarDump.csproj index ad12441..c009cdb 100644 --- a/src/VarDump.csproj +++ b/src/VarDump.csproj @@ -4,13 +4,13 @@ net45;netstandard2.0 latest VarDump - 0.2.7 - 0.2.7 + 0.2.8 + 0.2.8 Apache-2.0 Copyright $([System.DateTime]::Now.Year) Yevhen Cherkes True VarDump - 0.2.7 + 0.2.8 VarDump is a utility for serialization runtime objects to C# and Visual Basic string. https://github.com/ycherkes/VarDump README.md diff --git a/src/Visitor/KnownTypes/CollectionVisitor.cs b/src/Visitor/KnownTypes/CollectionVisitor.cs index 7d16996..aed0d94 100644 --- a/src/Visitor/KnownTypes/CollectionVisitor.cs +++ b/src/Visitor/KnownTypes/CollectionVisitor.cs @@ -93,9 +93,9 @@ private CodeExpression VisitSimpleCollection(IEnumerable enumerable, Type elemen var type = enumerable.GetType(); - var isImmutable = type.IsPublicImmutableCollection(); + var isImmutableOrFrozen = type.IsPublicImmutableOrFrozenCollection(); - if (type.IsArray || isImmutable || !IsCollection(enumerable)) + if (type.IsArray || isImmutableOrFrozen || !IsCollection(enumerable)) { if (type.IsArray && ((Array)enumerable).Rank > 1) { @@ -103,10 +103,10 @@ private CodeExpression VisitSimpleCollection(IEnumerable enumerable, Type elemen } CodeExpression expr = new CodeArrayCreateExpression( - new CodeTypeReference(isImmutable || !type.IsPublic ? elementType.MakeArrayType() : type, _typeReferenceOptions), + new CodeTypeReference(isImmutableOrFrozen || !type.IsPublic ? elementType.MakeArrayType() : type, _typeReferenceOptions), items.ToArray()); - if (isImmutable) expr = new CodeMethodInvokeExpression(expr, $"To{type.Name.Split('`')[0]}"); + if (isImmutableOrFrozen) expr = new CodeMethodInvokeExpression(expr, $"To{type.GetImmutableOrFrozenTypeName()}"); return expr; } @@ -155,7 +155,7 @@ private CodeExpression VisitAnonymousCollection(IEnumerable enumerable) var items = enumerable.Cast().Select(_rootObjectVisitor.Visit); var type = enumerable.GetType(); - var isImmutable = type.IsPublicImmutableCollection(); + var isImmutableOrFrozen = type.IsPublicImmutableOrFrozenCollection(); var typeReference = new CodeAnonymousTypeReference { ArrayRank = 1 }; @@ -169,8 +169,8 @@ private CodeExpression VisitAnonymousCollection(IEnumerable enumerable) typeReference, items.ToArray()); - if (isImmutable || enumerable is IList && !type.IsArray) - expr = new CodeMethodInvokeExpression(expr, $"To{type.Name.Split('`')[0]}"); + if (isImmutableOrFrozen || enumerable is IList && !type.IsArray) + expr = new CodeMethodInvokeExpression(expr, $"To{type.GetImmutableOrFrozenTypeName()}"); return expr; } diff --git a/src/Visitor/KnownTypes/DictionaryVisitor.cs b/src/Visitor/KnownTypes/DictionaryVisitor.cs index 0783c84..3aba408 100644 --- a/src/Visitor/KnownTypes/DictionaryVisitor.cs +++ b/src/Visitor/KnownTypes/DictionaryVisitor.cs @@ -59,9 +59,9 @@ private CodeExpression VisitSimpleDictionary(IDictionary dict) var items = dict.Cast().Select(VisitKeyValuePairGenerateImplicitly); var type = dict.GetType(); - var isImmutable = type.IsPublicImmutableCollection(); + var isImmutableOrFrozen = type.IsPublicImmutableOrFrozenCollection(); - if (isImmutable) + if (isImmutableOrFrozen) { var keyType = ReflectionUtils.GetInnerElementType(dict.Keys.GetType()); var valueType = ReflectionUtils.GetInnerElementType(dict.Values.GetType()); @@ -70,7 +70,7 @@ private CodeExpression VisitSimpleDictionary(IDictionary dict) CodeExpression dictionaryCreateExpression = new CodeObjectCreateAndInitializeExpression(new CodeCollectionTypeReference(dictionaryType, _typeReferenceOptions), items); - dictionaryCreateExpression = new CodeMethodInvokeExpression(dictionaryCreateExpression, $"To{type.Name.Split('`')[0]}"); + dictionaryCreateExpression = new CodeMethodInvokeExpression(dictionaryCreateExpression, $"To{type.GetImmutableOrFrozenTypeName()}"); return dictionaryCreateExpression; } @@ -94,10 +94,10 @@ private CodeExpression VisitAnonymousDictionary(IEnumerable dictionary) var keyLambdaExpression = new CodeLambdaExpression(new CodePropertyReferenceExpression(variableReferenceExpression, keyName), variableReferenceExpression); var valueLambdaExpression = new CodeLambdaExpression(new CodePropertyReferenceExpression(variableReferenceExpression, valueName), variableReferenceExpression); - var isImmutable = type.IsPublicImmutableCollection(); + var isImmutableOrFrozen = type.IsPublicImmutableOrFrozenCollection(); - expr = isImmutable - ? new CodeMethodInvokeExpression(expr, $"To{type.Name.Split('`')[0]}", keyLambdaExpression, valueLambdaExpression) + expr = isImmutableOrFrozen + ? new CodeMethodInvokeExpression(expr, $"To{type.GetImmutableOrFrozenTypeName()}", keyLambdaExpression, valueLambdaExpression) : new CodeMethodInvokeExpression(expr, "ToDictionary", keyLambdaExpression, valueLambdaExpression); return expr; diff --git a/src/VisualBasicDumper.cs b/src/VisualBasicDumper.cs index adaffce..2e4b2c2 100644 --- a/src/VisualBasicDumper.cs +++ b/src/VisualBasicDumper.cs @@ -36,6 +36,11 @@ public string Dump(object obj) public void Dump(object obj, TextWriter textWriter) { + if(textWriter == null) + { + throw new ArgumentNullException(nameof(textWriter)); + } + DumpImpl(obj, textWriter); } diff --git a/test/UnitTests/DataTableSpec.cs b/test/UnitTests/DataTableSpec.cs index b739a5d..883aefa 100644 --- a/test/UnitTests/DataTableSpec.cs +++ b/test/UnitTests/DataTableSpec.cs @@ -10,6 +10,8 @@ namespace UnitTests; +#if !NET8_0_OR_GREATER + public class DataTableSpec { [Fact(Skip = "Skip")] @@ -68,4 +70,6 @@ public void DumpDataTableCsharp() Assert.Equal(@"", result); } -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/test/UnitTests/FrozenCollectionsNet8Spec.cs b/test/UnitTests/FrozenCollectionsNet8Spec.cs new file mode 100644 index 0000000..b0d6d6f --- /dev/null +++ b/test/UnitTests/FrozenCollectionsNet8Spec.cs @@ -0,0 +1,97 @@ +#if NET8_0_OR_GREATER + +using System.Collections.Frozen; +using System.Collections.Generic; +using VarDump; +using Xunit; + +namespace UnitTests +{ + public class FrozenCollectionsNet8Spec + { + + [Fact] + public void DumpFrozenSetCsharp() + { + FrozenSet frozenSet = new[] { 1 }.ToFrozenSet(); + + var dumper = new CSharpDumper(); + + var result = dumper.Dump(frozenSet); + + Assert.Equal(""" + var smallValueTypeComparableFrozenSetOfInt = new int[] + { + 1 + }.ToFrozenSet(); + + """, result); + } + + [Fact] + public void DumpFrozenSetVb() + { + FrozenSet frozenSet = new[] { 1 }.ToFrozenSet(); + + var dumper = new VisualBasicDumper(); + + var result = dumper.Dump(frozenSet); + + Assert.Equal(""" + Dim smallValueTypeComparableFrozenSetOfInteger = New Integer(){ + 1 + }.ToFrozenSet() + + """, result); + } + + [Fact] + public void DumpFrozenDictionaryCsharp() + { + var frozenDictionary = new Dictionary + { + { "Steeve", "Test reference" } + }.ToFrozenDictionary(); + + var dumper = new CSharpDumper(); + + var result = dumper.Dump(frozenDictionary); + + Assert.Equal(""" + var lengthBucketsFrozenDictionaryOfString = new Dictionary + { + { + "Steeve", + "Test reference" + } + }.ToFrozenDictionary(); + + """, result); + } + + [Fact] + public void DumpFrozenDictionaryVb() + { + var frozenDictionary = new Dictionary + { + { "Steeve", "Test reference" } + }.ToFrozenDictionary(); + + var dumper = new VisualBasicDumper(); + + var result = dumper.Dump(frozenDictionary); + + Assert.Equal(""" + Dim lengthBucketsFrozenDictionaryOfString = New Dictionary(Of String, String) From { + { + "Steeve", + "Test reference" + } + }.ToFrozenDictionary() + + """, result); + } + } +} + +#endif \ No newline at end of file diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj index a93580e..1218d2a 100644 --- a/test/UnitTests/UnitTests.csproj +++ b/test/UnitTests/UnitTests.csproj @@ -1,7 +1,7 @@ - net6.0;net461 + net6.0;net8.0;net461 false latest