1 2 3 4 |
public class Person { public string Name { get; set; } } |
1 2 3 4 5 6 7 8 9 |
var o = new Person(); o.Name = "John"; Person p = o; p.Name = "Mary"; Response.Write(o.Name); //Output value is: Mary Response.Write(p.Name); //Output value is: Mary |
So, you ask, what happened to "John"? Well, you modified it. The problem is that the new person "p" in line# 4 is only a reference to variable "o". In essence, by modifying "p" you are modifying "o".
Now, if you have access to the code, you can turn it into a struct to avoid this from happening:
1 2 3 4 |
public struct Person { public string Name { get; set; } } |
Well, if you don't want a struct (Structure in VB), what you can do is add a function to the class to return a new copy of itself:
1 2 3 4 5 6 7 8 9 |
public class Person { public string Name { get; set; } public Person GetShallowCopy() { return new Person() { Name = this.Name }; } } |
1 2 3 4 5 6 7 8 9 |
var o = new Person(); o.Name = "John"; Person p = o.GetShallowCopy(); p.Name = "Mary"; Response.Write(o.Name); //Output value is: John Response.Write(p.Name); //Output value is: Mary |
As you can see, the GetShallowCopy() function creates a new object and copies the current values of its own container class. One problem with this is that you might have way too many properties or way too many classes and you don't want to do this in all of your classes. Another problem is that you might not have access to the code of the class that you want to shallow copy. For these scenarios, I use extension methods and reflection.
Create an extension method that looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
public static class Extensions { public static T GetShallowCopy<T>(this T obj) { T newObj = Activator.CreateInstance<T>(); var props = typeof(T).GetProperties(); var flds = typeof(T).GetFields(); foreach (PropertyInfo i in props) { if (i.CanRead && i.CanWrite) { object val = i.GetValue(obj, null); Type typ = i.PropertyType; if (typ.IsPrimitive || typ == typeof(string) || typ == typeof(DateTime)) { i.SetValue(newObj, val, null); } } } foreach (FieldInfo i in flds) { object val = i.GetValue(obj); Type typ = i.FieldType; if (typ.IsPrimitive || typ == typeof(string) || typ == typeof(DateTime)) { i.SetValue(newObj, val); } } return newObj; } } |
VB.NET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
Public Module Extensions <Extension()> _ Public Function GetShallowCopy(Of T)(ByRef obj As T) As T Dim newObj = Activator.CreateInstance(Of T)() Dim props = GetType(T).GetProperties() Dim flds = GetType(T).GetFields() For Each i As PropertyInfo In props If i.CanRead AndAlso i.CanWrite Then Dim val As Object = i.GetValue(obj, Nothing) Dim typ As Type = i.PropertyType If typ.IsPrimitive OrElse typ = GetType(String) OrElse typ = GetType(DateTime) Then i.SetValue(newObj, val, Nothing) End If End If Next For Each i As FieldInfo In flds Dim val As Object = i.GetValue(obj) Dim typ As Type = i.FieldType If typ.IsPrimitive OrElse typ = GetType(String) OrElse typ = GetType(DateTime) Then i.SetValue(newObj, val) End If Next Return newObj End Function End Module |
Here is a deep copy function too:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
public static Extensions { public static T GetDeepCopy<T>(this T obj) { var newObj = Activator.CreateInstance(obj.GetType()); var props = obj.GetType().GetProperties(); var flds = obj.GetType().GetFields(); foreach (PropertyInfo i in props) { if (i.CanRead) { object val = i.GetValue(obj, null); if (val == null) { continue; } if (val is string || val.GetType().IsPrimitive) { if (i.CanWrite) { i.SetValue(newObj, val, null); } } else { var n = val.GetDeepCopy(); if (i.CanWrite) { i.SetValue(newObj, n, null); } } } } foreach (FieldInfo i in flds) { object val = i.GetValue(obj); if (val == null) { continue; } if (val is string || val.GetType().IsPrimitive) { i.SetValue(newObj, val); } else { var n = val.GetDeepCopy(); i.SetValue(newObj, n); } } return (T)newObj; } } |
VB.NET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
Public Module Extensions <Extension()> _ Public Function GetDeepCopy(Of T)(ByRef obj As T) As T Dim newObj = Activator.CreateInstance(obj.GetType()) Dim props = obj.GetType().GetProperties() Dim flds = obj.GetType().GetFields() For Each i As PropertyInfo In props If i.CanRead Then Dim val As Object = i.GetValue(obj, Nothing) If val Is Nothing Then Continue For Dim typ As Type = i.PropertyType If typ.IsPrimitive OrElse typ = GetType(String) OrElse typ = GetType(DateTime) Then If i.CanWrite Then i.SetValue(newObj, val, Nothing) End If Else Dim n = GetDeepCopy(val) If i.CanWrite Then i.SetValue(newObj, n, Nothing) End If End If End If Next For Each i As FieldInfo In flds Dim val As Object = i.GetValue(obj) If val Is Nothing Then Continue For Dim typ As Type = i.FieldType If typ.IsPrimitive OrElse typ = GetType(String) OrElse typ = GetType(DateTime) Then i.SetValue(newObj, val) Else Dim n = GetDeepCopy(val) i.SetValue(newObj, n) End If Next Return CType(newObj, T) End Function End Module |
No comments:
Post a Comment