Skip to content

Commit 770af80

Browse files
committed
added system.reflection namespace to ignore, some refactoring
1 parent bfc90ae commit 770af80

9 files changed

+107
-34
lines changed

DeepCloner.Tests/ClrExceptionSpec.cs

-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
#if !NETCORE
22
using System;
33
using System.Collections.Generic;
4-
using System.Reflection;
5-
6-
using Force.DeepCloner.Helpers;
74

85
using NUnit.Framework;
96

DeepCloner.Tests/InheritanceSpec.cs

+69
Original file line numberDiff line numberDiff line change
@@ -237,5 +237,74 @@ public void Array_Of_Struct_Casted_To_Interface_Should_Be_Cloned()
237237
var clonedArr = arr.DeepClone();
238238
Assert.That(clonedArr[0], Is.EqualTo(clonedArr[1]));
239239
}
240+
241+
public class Safe1
242+
{
243+
}
244+
245+
public class Safe2
246+
{
247+
}
248+
249+
public class Unsafe1 : Safe1
250+
{
251+
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")]
252+
public object X;
253+
}
254+
255+
public class V1
256+
{
257+
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")]
258+
public Safe1 Safe;
259+
}
260+
261+
public class V2
262+
{
263+
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")]
264+
public Safe1 Safe;
265+
266+
public V2(string x)
267+
{
268+
}
269+
}
270+
271+
// these tests are overlapped by others, but for future can be helpful
272+
[Test]
273+
public void Class_With_Safe_Class_Should_Be_Cloned()
274+
{
275+
var v = new V1();
276+
v.Safe = new Safe1();
277+
var v2 = v.DeepClone();
278+
Assert.That(v.Safe == v2.Safe, Is.False);
279+
}
280+
281+
[Test]
282+
public void Class_With_Safe_Class_Should_Be_Cloned_No_Default_Constructor()
283+
{
284+
var v = new V2("X");
285+
v.Safe = new Safe1();
286+
var v2 = v.DeepClone();
287+
Assert.That(v.Safe == v2.Safe, Is.False);
288+
}
289+
290+
[Test]
291+
public void Class_With_UnSafe_Class_Should_Be_Cloned()
292+
{
293+
var v = new V1();
294+
v.Safe = new Unsafe1();
295+
var v2 = v.DeepClone();
296+
Assert.That(v.Safe == v2.Safe, Is.False);
297+
Assert.That(v2.Safe.GetType(), Is.EqualTo(typeof(Unsafe1)));
298+
}
299+
300+
[Test]
301+
public void Class_With_UnSafe_Class_Should_Be_Cloned_No_Default_Constructor()
302+
{
303+
var v = new V2("X");
304+
v.Safe = new Unsafe1();
305+
var v2 = v.DeepClone();
306+
Assert.That(v.Safe == v2.Safe, Is.False);
307+
Assert.That(v2.Safe.GetType(), Is.EqualTo(typeof(Unsafe1)));
308+
}
240309
}
241310
}

DeepCloner.nuspec

+3-3
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.1</version>
6+
<version>0.10.2</version>
77
<authors>force</authors>
88
<owners>force</owners>
99
<licenseUrl>https://github.com/force-net/DeepCloner/blob/develop/LICENSE</licenseUrl>
@@ -12,8 +12,8 @@
1212
<requireLicenseAcceptance>false</requireLicenseAcceptance>
1313
<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>
1414
<releaseNotes>
15-
Fixed cloning of COM objects, some internal structures (RuntimeType, Remoting). Trying to improve cloning for dotnet core, excluded some internal classes.
16-
As result, some EF queries can be deep cloned without errors.
15+
Removed System.Reflection namespace (especially System.Reflection.Emit) from cloning.
16+
More accurate checking for empty constructors.
1717
</releaseNotes>
1818
<copyright>Copyright by Force 2016-2017</copyright>
1919
<tags>.NET shallow deep clone DeepClone fast</tags>

DeepCloner/Helpers/ClonerToExprGenerator.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ private static object GenerateProcessMethod(Type type, bool isDeepClone)
6767

6868
foreach (var fieldInfo in fi)
6969
{
70-
if (isDeepClone && !DeepClonerSafeTypes.IsTypeSafe(fieldInfo.FieldType, null))
70+
if (isDeepClone && !DeepClonerSafeTypes.CanNotCopyType(fieldInfo.FieldType, null))
7171
{
7272
var methodInfo = fieldInfo.FieldType.IsValueType()
7373
? typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneStructInternal")
@@ -136,7 +136,7 @@ private static object GenerateProcessArrayMethod(Type type, bool isDeep)
136136
else
137137
{
138138
var methodName = "Clone1DimArrayClassInternal";
139-
if (DeepClonerSafeTypes.IsTypeSafe(elementType, null)) methodName = "Clone1DimArraySafeInternal";
139+
if (DeepClonerSafeTypes.CanNotCopyType(elementType, null)) methodName = "Clone1DimArraySafeInternal";
140140
else if (elementType.IsValueType()) methodName = "Clone1DimArrayStructInternal";
141141
var methodInfo = typeof(ClonerToExprGenerator).GetPrivateStaticMethod(methodName).MakeGenericMethod(elementType);
142142
var callS = Expression.Call(methodInfo, Expression.Convert(from, type), Expression.Convert(to, type), state);
@@ -204,7 +204,7 @@ internal static T[] Clone1DimArrayClassInternal<T>(T[] objFrom, T[] objTo, DeepC
204204
var l1 = Math.Min(objFrom.GetLength(0), objTo.GetLength(0));
205205
var l2 = Math.Min(objFrom.GetLength(1), objTo.GetLength(1));
206206
state.AddKnownRef(objFrom, objTo);
207-
if ((!isDeep || DeepClonerSafeTypes.IsTypeSafe(typeof(T), null))
207+
if ((!isDeep || DeepClonerSafeTypes.CanNotCopyType(typeof(T), null))
208208
&& objFrom.GetLength(0) == objTo.GetLength(0)
209209
&& objFrom.GetLength(1) == objTo.GetLength(1))
210210
{

DeepCloner/Helpers/DeepClonerExprGenerator.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ internal static class DeepClonerExprGenerator
99
{
1010
internal static object GenerateClonerInternal(Type realType, bool asObject)
1111
{
12-
if (DeepClonerSafeTypes.IsTypeSafe(realType, null)) return null;
12+
if (DeepClonerSafeTypes.CanNotCopyType(realType, null)) return null;
1313

1414
return GenerateProcessMethod(realType, asObject && realType.IsValueType());
1515
}
@@ -100,7 +100,7 @@ private static object GenerateProcessMethod(Type type, bool unboxStruct)
100100

101101
foreach (var fieldInfo in fi)
102102
{
103-
if (!DeepClonerSafeTypes.IsTypeSafe(fieldInfo.FieldType, null))
103+
if (!DeepClonerSafeTypes.CanNotCopyType(fieldInfo.FieldType, null))
104104
{
105105
var methodInfo = fieldInfo.FieldType.IsValueType()
106106
? typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneStructInternal")
@@ -164,7 +164,7 @@ private static object GenerateProcessArrayMethod(Type type)
164164
else
165165
{
166166
var methodName = "Clone1DimArrayClassInternal";
167-
if (DeepClonerSafeTypes.IsTypeSafe(elementType, null)) methodName = "Clone1DimArraySafeInternal";
167+
if (DeepClonerSafeTypes.CanNotCopyType(elementType, null)) methodName = "Clone1DimArraySafeInternal";
168168
else if (elementType.IsValueType()) methodName = "Clone1DimArrayStructInternal";
169169
methodInfo = typeof(DeepClonerGenerator).GetPrivateStaticMethod(methodName).MakeGenericMethod(elementType);
170170
}

DeepCloner/Helpers/DeepClonerGenerator.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ private static object CloneClassRoot(object obj)
2020
// we can receive an poco objects which is faster to copy in shallow way if possible
2121
var type = obj.GetType();
2222
// 200ms
23-
if (DeepClonerSafeTypes.IsClassSafe(type))
23+
if (DeepClonerSafeTypes.CanNotDeepCopyClass(type))
2424
return ShallowObjectCloner.CloneObject(obj);
2525
// 350ms
2626
var cloner = (Func<object, DeepCloneState, object>)DeepClonerCache.GetOrAddClass(type, t => GenerateCloner(t, true));
@@ -109,7 +109,7 @@ internal static T[] Clone1DimArrayClassInternal<T>(T[] obj, DeepCloneState state
109109
var l2 = obj.GetLength(1);
110110
var outArray = new T[l1, l2];
111111
state.AddKnownRef(obj, outArray);
112-
if (DeepClonerSafeTypes.IsTypeSafe(typeof(T), null))
112+
if (DeepClonerSafeTypes.CanNotCopyType(typeof(T), null))
113113
{
114114
Array.Copy(obj, outArray, obj.Length);
115115
return outArray;

DeepCloner/Helpers/DeepClonerMsilGenerator.cs

+14-14
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ internal static object GenerateClonerInternal(Type realType, bool asObject)
1717
// there is no performance penalties to cast objects to concrete type, but we can win in removing other conversions
1818
var methodType = asObject ? typeof(object) : realType;
1919

20-
if (DeepClonerSafeTypes.IsTypeSafe(realType, null)) return null;
20+
if (DeepClonerSafeTypes.CanNotCopyType(realType, null)) return null;
2121

2222
var mb = TypeCreationHelper.GetModuleBuilder();
2323
var dt = new DynamicMethod(
@@ -122,7 +122,18 @@ private static void GenerateProcessMethod(ILGenerator il, Type type, bool unboxS
122122

123123
foreach (var fieldInfo in fi)
124124
{
125-
if (!DeepClonerSafeTypes.IsTypeSafe(fieldInfo.FieldType, null))
125+
if (DeepClonerSafeTypes.CanNotCopyType(fieldInfo.FieldType, null))
126+
{
127+
// for good consturctor we use direct field copy anyway
128+
if (isGoodConstructor)
129+
{
130+
il.Emit(type.IsClass ? OpCodes.Ldloc : OpCodes.Ldloca_S, typeLocal);
131+
il.Emit(OpCodes.Ldarg_0);
132+
il.Emit(OpCodes.Ldfld, fieldInfo);
133+
il.Emit(OpCodes.Stfld, fieldInfo);
134+
}
135+
}
136+
else
126137
{
127138
il.Emit(type.IsClass ? OpCodes.Ldloc : OpCodes.Ldloca_S, typeLocal);
128139
if (structLoc == null) il.Emit(OpCodes.Ldarg_0);
@@ -137,17 +148,6 @@ private static void GenerateProcessMethod(ILGenerator il, Type type, bool unboxS
137148
il.Emit(OpCodes.Call, methodInfo);
138149
il.Emit(OpCodes.Stfld, fieldInfo);
139150
}
140-
else
141-
{
142-
// for good consturctor we use direct field copy
143-
if (isGoodConstructor)
144-
{
145-
il.Emit(type.IsClass ? OpCodes.Ldloc : OpCodes.Ldloca_S, typeLocal);
146-
il.Emit(OpCodes.Ldarg_0);
147-
il.Emit(OpCodes.Ldfld, fieldInfo);
148-
il.Emit(OpCodes.Stfld, fieldInfo);
149-
}
150-
}
151151
}
152152

153153
il.Emit(OpCodes.Ldloc, typeLocal);
@@ -200,7 +200,7 @@ private static void GenerateProcessArrayMethod(ILGenerator il, Type type)
200200
il.Emit(OpCodes.Ldloc, typeLocal);
201201
il.Emit(OpCodes.Call, typeof(DeepCloneState).GetMethod("AddKnownRef"));
202202

203-
if (DeepClonerSafeTypes.IsTypeSafe(elementType, null))
203+
if (DeepClonerSafeTypes.CanNotCopyType(elementType, null))
204204
{
205205
// Array.Copy(from, to, from.Length);
206206
il.Emit(OpCodes.Ldarg_0);

DeepCloner/Helpers/DeepClonerSafeTypes.cs

+12-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var x in
3030
}) KnownTypes.TryAdd(x, true);
3131
}
3232

33-
internal static bool IsTypeSafe(Type type, HashSet<Type> processingTypes)
33+
internal static bool CanNotCopyType(Type type, HashSet<Type> processingTypes)
3434
{
3535
bool isSafe;
3636
if (KnownTypes.TryGetValue(type, out isSafe)) return isSafe;
@@ -52,11 +52,18 @@ internal static bool IsTypeSafe(Type type, HashSet<Type> processingTypes)
5252
return true;
5353
}
5454

55-
if (type.FullName.StartsWith("System.Reflection.Emit") && type.Assembly == typeof(System.Reflection.Emit.OpCode).Assembly)
55+
if (type.FullName.StartsWith("System.Reflection.") && type.Assembly == typeof(PropertyInfo).Assembly)
5656
{
5757
KnownTypes.TryAdd(type, true);
5858
return true;
5959
}
60+
61+
// catched by previous condition
62+
/*if (type.FullName.StartsWith("System.Reflection.Emit") && type.Assembly == typeof(System.Reflection.Emit.OpCode).Assembly)
63+
{
64+
KnownTypes.TryAdd(type, true);
65+
return true;
66+
}*/
6067

6168
// this types are serious native resources, it is better not to clone it
6269
if (type.IsSubclassOf(typeof(System.Runtime.ConstrainedExecution.CriticalFinalizerObject)))
@@ -122,7 +129,7 @@ internal static bool IsTypeSafe(Type type, HashSet<Type> processingTypes)
122129
continue;
123130

124131
// not safe and not not safe. we need to go deeper
125-
if (!IsTypeSafe(fieldType, processingTypes))
132+
if (!CanNotCopyType(fieldType, processingTypes))
126133
{
127134
KnownTypes.TryAdd(type, false);
128135
return false;
@@ -136,7 +143,7 @@ internal static bool IsTypeSafe(Type type, HashSet<Type> processingTypes)
136143
/// <summary>
137144
/// Classes with only safe fields are safe for ShallowClone (if they root objects for copying)
138145
/// </summary>
139-
internal static bool IsClassSafe(Type type)
146+
internal static bool CanNotDeepCopyClass(Type type)
140147
{
141148
bool isSafe;
142149
if (KnownClasses.TryGetValue(type, out isSafe)) return isSafe;
@@ -158,7 +165,7 @@ internal static bool IsClassSafe(Type type)
158165
}
159166
while (tp != null);
160167

161-
if (fi.Any(fieldInfo => !IsTypeSafe(fieldInfo.FieldType, null)))
168+
if (fi.Any(fieldInfo => !CanNotCopyType(fieldInfo.FieldType, null)))
162169
{
163170
KnownClasses.TryAdd(type, false);
164171
return false;

DeepCloner/project.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.10.1-*",
2+
"version": "0.10.2-*",
33
"buildOptions": {
44
"debugType": "portable",
55
"optimize": true,

0 commit comments

Comments
 (0)