Reputation: 1384
I have a class which I'm trying to run a deep copy on. One of the members of this class is 'MeshContainers' which is an instance of MeshContainerCollection.
MeshContainerCollection<> inherits from my SceneObjectCollection<> class which inherits from List<>
What I noticed is that the source object has 1 item inside the meshcontainercollection while the cloned object has 0. When stepping through the DeepCopy process I noticed that when I try to get the fields for MeshContainerCollection, it doesn't find any. Now MeshContainerCollection doens't have any direct fields (only inherited fields) so I thought that was the problem.
But I use:
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
Which (afaik) should also return the private inherited members. I have looked through the existing BindingFlags but haven't been able to figure out if there is another BindingFlag I should use to get the inherited private fields.
Could someone tell me how I can manage to do a REAL deep copy?
Deep Copy method I'm using:
private static object Process(object obj)
{
if (obj == null)
return null;
Type type = obj.GetType();
if (type.IsValueType || type == typeof(string))
{
return obj;
}
else if (type.IsArray)
{
Type elementType = Type.GetType(
type.FullName.Replace("[]", string.Empty));
var array = obj as Array;
Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)
{
copied.SetValue(Process(array.GetValue(i)), i);
}
return Convert.ChangeType(copied, obj.GetType());
}
else if (type.IsClass)
{
object toret = FormatterServices.GetUninitializedObject(obj.GetType());
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
field.SetValue(toret, Process(fieldValue));
}
return toret;
}
else
throw new ArgumentException("Unknown type");
}
EDIT1: I prefer not to do this by serialization but by reflection.
Upvotes: 2
Views: 308
Reputation: 61442
As mentioned in GetFields documentation,
private fields on base classes are not returned.
Try this method instead:
public static IEnumerable<FieldInfo> GetAllFields(this Type type)
{
IEnumerable<FieldInfo> fields = type.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (type.BaseType == null)
return fields;
else
return GetAllFields(baseType).Concat(fields);
}
(you might want to rewrite it to avoid all the enumerables and concatenations, but you get the idea)
Upvotes: 1
Reputation: 15579
one of the ways that you could achieve this is by serializing the object and then deserializing it back.. write a function to do the same..
FYI, your class needs to be marked [Serializable]
for this..
there are some libraries out there that do the same.. Copyable is one of them.. I would suggest not to try and reinvent the wheel rather build up on this library as there are too many edge conditions to handle when you deep copy.. may be you can submit patches to the author too..
Upvotes: 0