Skip to content

Commit 63784e0

Browse files
committed
support ignoring types globally
1 parent 955a7ff commit 63784e0

File tree

8 files changed

+1248
-155
lines changed

8 files changed

+1248
-155
lines changed

FastCloner.Tests/IgnoredTypesTests.cs

Lines changed: 668 additions & 0 deletions
Large diffs are not rendered by default.

FastCloner.Tests/SpecialCaseTests.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,6 +1989,57 @@ public bool HasPropertyChangedSubscribers()
19891989
}
19901990
}
19911991

1992+
struct ClonerIgnoreStructTest
1993+
{
1994+
[FastClonerIgnore]
1995+
public int MyInt;
1996+
}
1997+
1998+
struct ClonerIgnoreStructTestNullable
1999+
{
2000+
[FastClonerIgnore]
2001+
public int? MyInt;
2002+
}
2003+
2004+
[Test]
2005+
public void CloneSimpleInt()
2006+
{
2007+
int i = 42.DeepClone();
2008+
Assert.That(i, Is.EqualTo(42));
2009+
}
2010+
2011+
[Test]
2012+
public void StructMembersIgnoreNullable()
2013+
{
2014+
// Arrange
2015+
ClonerIgnoreStructTestNullable inst = new ClonerIgnoreStructTestNullable
2016+
{
2017+
MyInt = 49
2018+
};
2019+
2020+
// Act
2021+
ClonerIgnoreStructTestNullable cloned = inst.DeepClone();
2022+
2023+
// Assert
2024+
Assert.That(cloned.MyInt, Is.EqualTo(null), "Should ignore the field");
2025+
}
2026+
2027+
[Test]
2028+
public void StructMembersIgnore()
2029+
{
2030+
// Arrange
2031+
ClonerIgnoreStructTest inst = new ClonerIgnoreStructTest
2032+
{
2033+
MyInt = 49
2034+
};
2035+
2036+
// Act
2037+
ClonerIgnoreStructTest cloned = inst.DeepClone();
2038+
2039+
// Assert
2040+
Assert.That(cloned.MyInt, Is.EqualTo(0), "Should ignore the field");
2041+
}
2042+
19922043
[Test]
19932044
public void EventPropertyNotifyChangedIgnore()
19942045
{

FastCloner/Code/ClonerToExprGenerator.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ internal static class ClonerToExprGenerator
77
{
88
internal static object GenerateClonerInternal(Type realType, bool isDeepClone)
99
{
10-
if (realType.IsValueType())
11-
throw new InvalidOperationException("Operation is valid only for reference types");
12-
return GenerateProcessMethod(realType, isDeepClone);
10+
return realType.IsValueType() ? throw new InvalidOperationException("Operation is valid only for reference types") : GenerateProcessMethod(realType, isDeepClone);
1311
}
1412

1513
private static object GenerateProcessMethod(Type type, bool isDeepClone)

FastCloner/Code/FastClonerCache.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ namespace FastCloner.Code;
55

66
internal static class FastClonerCache
77
{
8+
internal static readonly ConcurrentDictionary<Type, bool> AlwaysIgnoredTypes = [];
9+
10+
internal static bool IsTypeIgnored(Type type)
11+
{
12+
return AlwaysIgnoredTypes.TryGetValue(type, out _);
13+
}
14+
815
private static readonly ClrCache<object?> classCache = new ClrCache<object?>();
916
private static readonly ClrCache<object?> structCache = new ClrCache<object?>();
1017
private static readonly ClrCache<object> deepClassToCache = new ClrCache<object>();
@@ -14,7 +21,8 @@ internal static class FastClonerCache
1421
private static readonly ClrCache<Dictionary<string, Type>> ignoredEventInfoCache = new ClrCache<Dictionary<string, Type>>();
1522
private static readonly ClrCache<List<MemberInfo>> allMembersCache = new ClrCache<List<MemberInfo>>();
1623
private static readonly GenericClrCache<MemberInfo, bool> memberIgnoreStatusCache = new GenericClrCache<MemberInfo, bool>();
17-
24+
private static readonly ClrCache<bool> typeContainsIgnoredMembersCache = new ClrCache<bool>();
25+
1826
public static object? GetOrAddField(Type type, Func<Type, object?> valueFactory) => fieldCache.GetOrAdd(type, valueFactory);
1927
public static object? GetOrAddClass(Type type, Func<Type, object?> valueFactory) => classCache.GetOrAdd(type, valueFactory);
2028
public static object? GetOrAddStructAsObject(Type type, Func<Type, object?> valueFactory) => structCache.GetOrAdd(type, valueFactory);
@@ -24,6 +32,10 @@ internal static class FastClonerCache
2432
public static Dictionary<string, Type> GetOrAddIgnoredEventInfo(Type type, Func<Type, Dictionary<string, Type>> valueFactory) => ignoredEventInfoCache.GetOrAdd(type, valueFactory);
2533
public static List<MemberInfo> GetOrAddAllMembers(Type type, Func<Type, List<MemberInfo>> valueFactory) => allMembersCache.GetOrAdd(type, valueFactory);
2634
public static bool GetOrAddMemberIgnoreStatus(MemberInfo memberInfo, Func<MemberInfo, bool> valueFactory) => memberIgnoreStatusCache.GetOrAdd(memberInfo, valueFactory);
35+
public static bool GetOrAddTypeContainsIgnoredMembers(Type type, Func<Type, bool> valueFactory)
36+
{
37+
return type.IsValueType && typeContainsIgnoredMembersCache.GetOrAdd(type, valueFactory);
38+
}
2739

2840
/// <summary>
2941
/// Clears the FastCloner cached reflection metadata.

0 commit comments

Comments
 (0)