Skip to content

Commit e2e19be

Browse files
committed
Issue #17 hotfix for comparers
1 parent 2c1ff62 commit e2e19be

File tree

7 files changed

+92
-19
lines changed

7 files changed

+92
-19
lines changed

DeepCloner.Tests/ArraysSpec.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
35
using System.Text;
46

57
using NUnit.Framework;
@@ -358,5 +360,51 @@ public void MultiDimensional_Array_Should_Be_Cloned()
358360
Array.CreateInstance(typeof(int), new[] { 0, 0, 1 }).DeepClone();
359361
Array.CreateInstance(typeof(int), new[] { 1, 1, 1 }).DeepClone();
360362
}
363+
364+
[Test]
365+
public void Issue_17_Spec()
366+
{
367+
var set = new HashSet<string> { "value" };
368+
Assert.That(set.Contains("value"), Is.True);
369+
370+
var cloned = set.DeepClone();
371+
Assert.That(cloned.Contains("value"), Is.True);
372+
373+
var copyOfSet = new HashSet<string>(set, set.Comparer);
374+
Assert.That(copyOfSet.Contains("value"), Is.True);
375+
376+
var copyOfCloned = new HashSet<string>(cloned, cloned.Comparer);
377+
Assert.That(copyOfCloned.ToArray()[0] == "value", Is.True);
378+
379+
Assert.That(copyOfCloned.Contains("value"), Is.True);
380+
}
381+
382+
[Test]
383+
public void Check_Comparer_does_not_Clone()
384+
{
385+
Check_Comparer_does_not_Clone_Internal<string>();
386+
Check_Comparer_does_not_Clone_Internal<int>();
387+
Check_Comparer_does_not_Clone_Internal<object>();
388+
Check_Comparer_does_not_Clone_Internal<FileShare>();
389+
Check_Comparer_does_not_Clone_Internal<byte[]>();
390+
Check_Comparer_does_not_Clone_Internal<byte>();
391+
Check_Comparer_does_not_Clone_Internal<int?>();
392+
Check_Comparer_does_not_Clone_Internal<HashSet<int>>();
393+
Assert.That(StringComparer.Ordinal == StringComparer.Ordinal.DeepClone(), Is.True);
394+
Assert.That(StringComparer.OrdinalIgnoreCase == StringComparer.OrdinalIgnoreCase.DeepClone(), Is.True);
395+
Assert.That(StringComparer.InvariantCulture == StringComparer.InvariantCulture.DeepClone(), Is.True);
396+
Assert.That(StringComparer.InvariantCultureIgnoreCase == StringComparer.InvariantCultureIgnoreCase.DeepClone(), Is.True);
397+
Assert.That(StringComparer.CurrentCulture == StringComparer.CurrentCulture.DeepClone(), Is.True);
398+
Assert.That(StringComparer.CurrentCultureIgnoreCase == StringComparer.CurrentCultureIgnoreCase.DeepClone(), Is.True);
399+
}
400+
401+
private void Check_Comparer_does_not_Clone_Internal<T>()
402+
{
403+
var comparer = EqualityComparer<T>.Default;
404+
var cloned = comparer.DeepClone();
405+
406+
// checking by reference
407+
Assert.That(comparer == cloned, Is.True);
408+
}
361409
}
362410
}

DeepCloner.Tests/DeepCloner.Tests.Core.csproj

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFrameworks>netcoreapp1.0;netcoreapp2.0;net461</TargetFrameworks>
3+
<TargetFrameworks>netcoreapp2.0;netcoreapp3.1;netcoreapp6.0;net461</TargetFrameworks>
44
<DebugType>portable</DebugType>
55
<AssemblyName>DeepCloner.NET.Tests</AssemblyName>
66
<OutputType>Library</OutputType>
@@ -26,6 +26,12 @@
2626
<PackageReference Include="EntityFramework" Version="6.1.3" />
2727
<PackageReference Include="ServiceStack" Version="5.9.2" />
2828
</ItemGroup>
29+
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp6.0'">
30+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" />
31+
</ItemGroup>
32+
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1'">
33+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" />
34+
</ItemGroup>
2935
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0'">
3036
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" />
3137
</ItemGroup>
@@ -36,11 +42,17 @@
3642
<Reference Include="System.Windows.Forms" />
3743
</ItemGroup>
3844
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">
39-
<DefineConstants>$(DefineConstants);NETCORE;;NETCORE13</DefineConstants>
45+
<DefineConstants>$(DefineConstants);NETCORE;NETCORE13</DefineConstants>
4046
</PropertyGroup>
4147
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
4248
<DefineConstants>$(DefineConstants);NETCORE;NETCORE20</DefineConstants>
4349
</PropertyGroup>
50+
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
51+
<DefineConstants>$(DefineConstants);NETCORE;NETCORE31</DefineConstants>
52+
</PropertyGroup>
53+
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp6.0' ">
54+
<DefineConstants>$(DefineConstants);NETCORE;NETCORE60</DefineConstants>
55+
</PropertyGroup>
4456
<PropertyGroup>
4557
<DefineConstants>$(DefineConstants);COREVERSION</DefineConstants>
4658
</PropertyGroup>

DeepCloner.Tests/SystemTypesSpec.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ public void Type_With_Native_Resource_Should_Be_Cloned()
4444
try
4545
{
4646
var writer = File.CreateText(fileName);
47-
writer.AutoFlush = true;
47+
writer.AutoFlush = true;
4848
writer.Write("1");
4949
var cloned = writer.DeepClone();
5050
writer.Write("2");
51-
cloned.Write(3);
51+
cloned.Write("3");
5252
#if !NETCORE
5353
var f = typeof(FileStream).GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance);
5454
var f2 = typeof(SafeHandle).GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance);
@@ -63,7 +63,13 @@ public void Type_With_Native_Resource_Should_Be_Cloned()
6363

6464
Assert.Throws<ObjectDisposedException>(cloned.Flush);
6565
var res = File.ReadAllText(fileName);
66+
#if NETCORE60
67+
// it uses RandomAccess.WriteAtOffset(this._fileHandle, buffer, this._filePosition); - and offset of cloned file
68+
// is preserved, so, 2 will disappear
69+
Assert.That(res, Is.EqualTo("13"));
70+
#else
6671
Assert.That(res, Is.EqualTo("123"));
72+
#endif
6773
}
6874
finally
6975
{

DeepCloner.nuspec

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<metadata>
44
<id>DeepCloner</id>
55
<title>DeepCloner</title>
6-
<version>0.10.3</version>
6+
<version>0.10.4</version>
77
<authors>force</authors>
88
<owners>force</owners>
99
<license type="expression">MIT</license>
@@ -15,17 +15,9 @@
1515
<description>Small Library for fast deep or shallow cloning .NET objects. It allows to copy everything and has a lot of performance tricks for fast copying.</description>
1616
<summary>Small Library for fast deep or shallow cloning .NET objects.</summary>
1717
<releaseNotes>
18-
Custom dictionary implementation for faster reference counting (and faster cloning)
19-
Excluded DBNull from cloning
20-
Rewrited code for more correct cloning of objects forbidden for cloning (mainly for Shallow cloning)
21-
Better handling for stucts casted to object
22-
Increased speed for cloning simple tuples
23-
Added some protection for parallel cloning objects with readonly fields
24-
Optimized copying readonly fields for .net core
25-
Fixed copying multi-dim arrays with 0-length of some dimension
26-
2-dim arrays were processed by generic (non-optimized) way
18+
Excluded default comparers from cloning. Main fix for .NET6 and HashSet&lt;string&gt; but some other cases can be fixed too.
2719
</releaseNotes>
28-
<copyright>Copyright by Force 2016-2021</copyright>
20+
<copyright>Copyright by Force 2016-2022</copyright>
2921
<tags>.NET shallow deep clone DeepClone fast</tags>
3022
<dependencies>
3123
<group targetFramework="net40">

DeepCloner/DeepCloner.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<VersionPrefix>0.10.3</VersionPrefix>
3+
<VersionPrefix>0.10.4</VersionPrefix>
44
<TargetFrameworks>netstandard1.3;net40</TargetFrameworks>
55
<GenerateDocumentationFile>true</GenerateDocumentationFile>
66
<AssemblyName>DeepCloner</AssemblyName>

DeepCloner/Helpers/DeepClonerSafeTypes.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ var x in
2525
// do not clone such native type
2626
Type.GetType("System.RuntimeType"),
2727
Type.GetType("System.RuntimeTypeHandle"),
28+
StringComparer.Ordinal.GetType(),
29+
StringComparer.CurrentCulture.GetType(), // CultureAwareComparer - can be same
2830
#if !NETCORE
2931
typeof(DBNull)
3032
#endif
@@ -119,6 +121,19 @@ private static bool CanReturnSameType(Type type, HashSet<Type> processingTypes)
119121
return true;
120122
}
121123
#endif
124+
// default comparers should not be cloned due possible comparison EqualityComparer<T>.Default == comparer
125+
if (type.FullName.Contains("EqualityComparer"))
126+
{
127+
if (type.FullName.StartsWith("System.Collections.Generic.GenericEqualityComparer`")
128+
|| type.FullName.StartsWith("System.Collections.Generic.ObjectEqualityComparer`")
129+
|| type.FullName.StartsWith("System.Collections.Generic.EnumEqualityComparer`")
130+
|| type.FullName.StartsWith("System.Collections.Generic.NullableEqualityComparer`")
131+
|| type.FullName == "System.Collections.Generic.ByteEqualityComparer")
132+
{
133+
KnownTypes.TryAdd(type, true);
134+
return true;
135+
}
136+
}
122137

123138
// classes are always unsafe (we should copy it fully to count references)
124139
if (!type.IsValueType())

DeepCloner/Properties/AssemblyInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
[assembly: AssemblyConfiguration("")]
1010
[assembly: AssemblyCompany("Force")]
1111
[assembly: AssemblyProduct("DeepCloner")]
12-
[assembly: AssemblyCopyright("Copyright © Force 2016-2021")]
12+
[assembly: AssemblyCopyright("Copyright © Force 2016-2022")]
1313
[assembly: AssemblyTrademark("")]
1414
[assembly: AssemblyCulture("")]
1515

@@ -32,8 +32,8 @@
3232
// by using the '*' as shown below:
3333

3434
[assembly: AssemblyVersion("0.10.0.0")] // change this value only when api is changing
35-
[assembly: AssemblyFileVersion("0.10.3.0")]
36-
[assembly: AssemblyInformationalVersion("0.10.3.0")]
35+
[assembly: AssemblyFileVersion("0.10.4.0")]
36+
[assembly: AssemblyInformationalVersion("0.10.4.0")]
3737

3838
#if BUILDCORE
3939
// [assembly: AssemblyKeyFileAttribute("..\\public.snk")]

0 commit comments

Comments
 (0)