Skip to content

Commit 7aa1f48

Browse files
committed
Fixes up some cloning with value types and collections
1 parent 998f031 commit 7aa1f48

File tree

4 files changed

+38
-14
lines changed

4 files changed

+38
-14
lines changed

src/Umbraco.Core/Models/DeepCloneHelper.cs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ public static void DeepCloneRefProperties(IDeepCloneable input, IDeepCloneable o
4848
{
4949
IList newList;
5050
if (propertyInfo.PropertyType.IsGenericType
51-
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof (IEnumerable<>)
52-
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof (ICollection<>)
51+
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
52+
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
5353
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
5454
{
5555
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
56-
var genericType = typeof (List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
57-
newList = (IList) Activator.CreateInstance(genericType);
56+
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
57+
newList = (IList)Activator.CreateInstance(genericType);
5858
}
5959
else if (propertyInfo.PropertyType.IsArray
6060
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
@@ -86,22 +86,37 @@ public static void DeepCloneRefProperties(IDeepCloneable input, IDeepCloneable o
8686
var enumerable = (IEnumerable)propertyInfo.GetValue(input, null);
8787
if (enumerable == null) continue;
8888

89-
var isDeepClonableItems = false;
89+
var isUsableType = true;
90+
91+
//now clone each item
9092
foreach (var o in enumerable)
9193
{
94+
//first check if the item is deep cloneable and copy that way
9295
var dc = o as IDeepCloneable;
9396
if (dc != null)
9497
{
95-
isDeepClonableItems = true;
9698
newList.Add(dc.DeepClone());
9799
}
98-
else if (isDeepClonableItems)
100+
else if (o is string || o.GetType().IsValueType)
101+
{
102+
//check if the item is a value type or a string, then we can just use it
103+
newList.Add(o);
104+
}
105+
else
99106
{
100-
//if not all items are deep cloneable throw an exception
101-
throw new InvalidOperationException("Cannot deep clone items in a collection that are not all " + typeof(IDeepCloneable));
107+
//this will occur if the item is not a string or value type or IDeepCloneable, in this case we cannot
108+
// clone each element, we'll need to skip this property, people will have to manually clone this list
109+
isUsableType = false;
110+
break;
102111
}
103112
}
104113

114+
//if this was not usable, skip this property
115+
if (isUsableType == false)
116+
{
117+
continue;
118+
}
119+
105120
if (propertyInfo.PropertyType.IsArray)
106121
{
107122
//need to convert to array

src/Umbraco.Tests/Models/DeepCloneHelperTests.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,19 @@ public void Cannot_Deep_Clone_Collection_Properties_That_Are_Not_Cloneable()
146146
{
147147
var test1 = new Test3()
148148
{
149-
MyTest1 = new object[] { new Test1(), "hello" }
149+
MyTest1 = new object[]
150+
{
151+
new Test1(), "hello",
152+
//not cloneable so this property will get skipped
153+
new Test2()
154+
}
150155
};
151156

152-
Assert.Throws<InvalidOperationException>(() => test1.DeepClone());
153-
157+
var clone = (Test3)test1.DeepClone();
158+
159+
//it skipped this property so these will now be the same
160+
Assert.AreSame(clone.MyTest1, test1.MyTest1);
161+
154162
}
155163

156164
public class Test1 : BaseCloneable

src/Umbraco.Tests/Models/UserTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public void Can_Deep_Clone()
2828
LastLockoutDate = DateTime.Now,
2929
LastLoginDate = DateTime.Now,
3030
LastPasswordChangeDate = DateTime.Now,
31-
Password = "test pass",
32-
PasswordAnswer = "answer",
31+
//Password = "test pass",
32+
//PasswordAnswer = "answer",
3333
PasswordQuestion = "question",
3434
//ProviderUserKey = "user key",
3535
SessionTimeout = 5,

src/Umbraco.Tests/Models/UserTypeTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using NUnit.Framework;
34
using Umbraco.Core.Models.Membership;
45

0 commit comments

Comments
 (0)