Skip to content

Commit 9ad9417

Browse files
committed
fallback safe variant, based on expressions
1 parent 99ba167 commit 9ad9417

22 files changed

+271
-125
lines changed

DeepCloner.Tests/ArraysSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55

66
namespace Force.DeepCloner.Tests
77
{
8-
[TestFixture]
9-
public class ArraysSpec
8+
[TestFixture(false)]
9+
[TestFixture(true)]
10+
public class ArraysSpec : BaseTest
1011
{
12+
public ArraysSpec(object isSafeInit)
13+
: base((bool)isSafeInit)
14+
{
15+
}
16+
1117
[Test]
1218
public void IntArray_Should_Be_Cloned()
1319
{

DeepCloner.Tests/BaseTest.cs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Reflection;
2+
3+
using Force.DeepCloner.Helpers;
4+
5+
namespace Force.DeepCloner.Tests
6+
{
7+
public class BaseTest
8+
{
9+
public BaseTest(bool isSafeInit)
10+
{
11+
SwitchTo(isSafeInit);
12+
}
13+
14+
public static void SwitchTo(bool isSafeInit)
15+
{
16+
typeof(ShallowObjectCloner).GetMethod("SwitchTo", BindingFlags.NonPublic | BindingFlags.Static)
17+
.Invoke(null, new object[] { isSafeInit });
18+
}
19+
}
20+
}

DeepCloner.Tests/CloneExtensionsSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44

55
namespace Force.DeepCloner.Tests
66
{
7-
[TestFixture]
8-
public class CloneExtensionsSpec
7+
[TestFixture(false)]
8+
[TestFixture(true)]
9+
public class CloneExtensionsSpec : BaseTest
910
{
11+
public CloneExtensionsSpec(bool isSafeInit)
12+
: base(isSafeInit)
13+
{
14+
}
15+
1016
public class C1
1117
{
1218
public int X { get; set; }

DeepCloner.Tests/ConstructorsSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44

55
namespace Force.DeepCloner.Tests
66
{
7-
[TestFixture]
8-
public class ConstructorsSpec
7+
[TestFixture(false)]
8+
[TestFixture(true)]
9+
public class ConstructorsSpec : BaseTest
910
{
11+
public ConstructorsSpec(bool isSafeInit)
12+
: base(isSafeInit)
13+
{
14+
}
15+
1016
public class T1
1117
{
1218
private T1()

DeepCloner.Tests/DeepCloner.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
</ItemGroup>
5050
<ItemGroup>
5151
<Compile Include="ArraysSpec.cs" />
52+
<Compile Include="BaseTest.cs" />
5253
<Compile Include="CloneExtensionsSpec.cs" />
5354
<Compile Include="ConstructorsSpec.cs" />
5455
<Compile Include="GenericsSpec.cs" />

DeepCloner.Tests/GenericsSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44

55
namespace Force.DeepCloner.Tests
66
{
7-
[TestFixture]
8-
public class GenericsSpec
7+
[TestFixture(false)]
8+
[TestFixture(true)]
9+
public class GenericsSpec : BaseTest
910
{
11+
public GenericsSpec(bool isSafeInit)
12+
: base(isSafeInit)
13+
{
14+
}
15+
1016
[Test]
1117
public void Tuple_Should_Be_Cloned()
1218
{

DeepCloner.Tests/InheritanceSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55

66
namespace Force.DeepCloner.Tests
77
{
8-
[TestFixture]
9-
public class InheritanceSpec
8+
[TestFixture(false)]
9+
[TestFixture(true)]
10+
public class InheritanceSpec : BaseTest
1011
{
12+
public InheritanceSpec(bool isSafeInit)
13+
: base(isSafeInit)
14+
{
15+
}
16+
1117
public class C1 : IDisposable
1218
{
1319
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")]

DeepCloner.Tests/LoopCheckSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22

33
namespace Force.DeepCloner.Tests
44
{
5-
[TestFixture]
6-
public class LoopCheckSpec
5+
[TestFixture(false)]
6+
[TestFixture(true)]
7+
public class LoopCheckSpec : BaseTest
78
{
9+
public LoopCheckSpec(bool isSafeInit)
10+
: base(isSafeInit)
11+
{
12+
}
13+
814
public class C1
915
{
1016
public int F { get; set; }

DeepCloner.Tests/PerformanceSpec.cs

+17-3
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,12 @@ private T CloneViaFormatter<T>(T obj)
5959
}
6060

6161
[Test, Ignore("Manual")]
62-
public void Test_Construct_Variants()
62+
[TestCase(false)]
63+
[TestCase(true)]
64+
public void Test_Construct_Variants(bool isSafe)
6365
{
66+
// we cache cloners for type, so, this only variant with separate run
67+
BaseTest.SwitchTo(isSafe);
6468
var c1 = new C1 { V1 = 1 };
6569
// warm up
6670
for (var i = 0; i < 1000; i++) ManualDeepClone(c1);
@@ -137,6 +141,9 @@ public void Test_Shallow_Variants()
137141
// warm up
138142
for (var i = 0; i < 1000; i++) ManualShallowClone(c1);
139143
for (var i = 0; i < 1000; i++) c1.Clone();
144+
BaseTest.SwitchTo(false);
145+
for (var i = 0; i < 1000; i++) c1.ShallowClone();
146+
BaseTest.SwitchTo(true);
140147
for (var i = 0; i < 1000; i++) c1.ShallowClone();
141148
for (var i = 0; i < 1000; i++) c1.GetClone();
142149

@@ -150,10 +157,17 @@ public void Test_Shallow_Variants()
150157

151158
for (var i = 0; i < 1000000; i++) c1.Clone();
152159
Console.WriteLine("Auto Internal: " + sw.ElapsedMilliseconds);
153-
sw.Restart();
160+
sw.Reset();
161+
BaseTest.SwitchTo(false);
162+
sw.Start();
163+
for (var i = 0; i < 1000000; i++) c1.ShallowClone();
164+
Console.WriteLine("Shallow Unsafe: " + sw.ElapsedMilliseconds);
165+
sw.Reset();
154166

167+
BaseTest.SwitchTo(true);
168+
sw.Start();
155169
for (var i = 0; i < 1000000; i++) c1.ShallowClone();
156-
Console.WriteLine("Shallow: " + sw.ElapsedMilliseconds);
170+
Console.WriteLine("Shallow Safe: " + sw.ElapsedMilliseconds);
157171
sw.Restart();
158172

159173
for (var i = 0; i < 1000000; i++) c1.GetClone(CloningFlags.Shallow);

DeepCloner.Tests/PermissionSpec.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq.Expressions;
4-
using System.Reflection;
53
using System.Security;
64
using System.Security.Permissions;
75

@@ -28,12 +26,12 @@ public void EnsurePermission()
2826
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
2927

3028
permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess | ReflectionPermissionFlag.MemberAccess));
31-
32-
// permissions.AddPermission(new SecurityPermission(PermissionState.Unrestricted));
29+
// permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
3330

3431
var test = AppDomain.CreateDomain("sandbox", null, setup, permissions);
3532

3633
var instance = (Executor)test.CreateInstanceFromAndUnwrap(this.GetType().Assembly.Location, typeof(Executor).FullName);
34+
instance.DoShallowClone();
3735
instance.DoDeepClone();
3836
}
3937

DeepCloner.Tests/ShallowClonerSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@
66

77
namespace Force.DeepCloner.Tests
88
{
9-
[TestFixture]
10-
public class ShallowClonerSpec
9+
[TestFixture(false)]
10+
[TestFixture(true)]
11+
public class ShallowClonerSpec : BaseTest
1112
{
13+
public ShallowClonerSpec(bool isSafeInit)
14+
: base(isSafeInit)
15+
{
16+
}
17+
1218
[Test]
1319
public void SimpleObject_Should_Be_Cloned()
1420
{

DeepCloner.Tests/SimpleObjectSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@
77

88
namespace Force.DeepCloner.Tests
99
{
10-
[TestFixture]
11-
public class SimpleObjectSpec
10+
[TestFixture(true)]
11+
[TestFixture(false)]
12+
public class SimpleObjectSpec : BaseTest
1213
{
14+
public SimpleObjectSpec(bool isSafeInit)
15+
: base(isSafeInit)
16+
{
17+
}
18+
1319
[Test]
1420
public void SimpleObject_Should_Be_Cloned()
1521
{

DeepCloner.Tests/StandardTypesSpec.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@
99

1010
namespace Force.DeepCloner.Tests
1111
{
12-
[TestFixture]
13-
public class StandardTypesSpec
12+
[TestFixture(false)]
13+
[TestFixture(true)]
14+
public class StandardTypesSpec : BaseTest
1415
{
16+
public StandardTypesSpec(bool isSafeInit)
17+
: base(isSafeInit)
18+
{
19+
}
20+
1521
[Test]
1622
public void StandardTypes_Should_Be_Cloned()
1723
{

DeepCloner.nuspec

+2-1
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.8.2</version>
6+
<version>0.9.0</version>
77
<authors>force</authors>
88
<owners>force</owners>
99
<licenseUrl>https://github.com/force-net/DeepCloner/blob/develop/LICENSE</licenseUrl>
@@ -14,6 +14,7 @@
1414
<releaseNotes>
1515
Fixed an issue with handling references to arrays
1616
Added support for multidimensional arrays and non-zero-based arrays
17+
Added fallback for non-fulltrust code through expressions
1718
</releaseNotes>
1819
<copyright>Copyright by Force 2016</copyright>
1920
<tags>.NET shallow deep clone</tags>

DeepCloner/DeepClonerExtensions.cs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Security;
1+
using System;
2+
using System.Security;
23

34
using Force.DeepCloner.Helpers;
45

@@ -12,7 +13,6 @@ public static class DeepClonerExtensions
1213
/// <summary>
1314
/// Performs deep (full) copy of object and related graph
1415
/// </summary>
15-
// [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] // <-- this attribute slowers execution
1616
public static T DeepClone<T>(this T obj)
1717
{
1818
return DeepClonerGenerator.CloneObject(obj);
@@ -21,7 +21,6 @@ public static T DeepClone<T>(this T obj)
2121
/// <summary>
2222
/// Performs shallow (only new object returned, without cloning of dependencies) copy of object
2323
/// </summary>
24-
// [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] // <-- this attribute slowers execution
2524
public static T ShallowClone<T>(this T obj)
2625
{
2726
return ShallowClonerGenerator.CloneObject(obj);
@@ -31,7 +30,7 @@ static DeepClonerExtensions()
3130
{
3231
if (!PermissionCheck())
3332
{
34-
throw new SecurityException("DeepCloner should have enough permissions to run. FullTrust set is enough to run.");
33+
throw new SecurityException("DeepCloner should have enough permissions to run. Grant FullTrust or Reflection permission.");
3534
}
3635
}
3736

@@ -47,6 +46,10 @@ private static bool PermissionCheck()
4746
{
4847
return false;
4948
}
49+
catch (MemberAccessException)
50+
{
51+
return false;
52+
}
5053

5154
return true;
5255
}

0 commit comments

Comments
 (0)