6

I have finally managed to copy a value type of my object, A class that uses a dictionary to store dynamic properties. I was wondering about two things though, mono compatibility and efficiency. I am new to C# and still have plenty to learn about programming in general, so apologies if I am misusing a few phrases :P

I used this method How do you do a deep copy of an object in .NET (C# specifically)? ... to copy my object. I will also have hundreds of these objects, and was wondering copying them in this fashion was very inefficient? Would structs be a better option? I am not sure when to use structs however. An could it be ported with mono? Some googling suggest this serialisation could give rise to a problem.

Community
  • 1
  • 1
marked
  • 589
  • 9
  • 24
  • @marked, Are you aware of the [ExpandoObject](http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx) ? – smartcaveman Jun 09 '11 at 16:35
  • 3
    This is one of the most glaring deficiencies in .NET. It absolutely should support memory copy cloning for deep cloning objects, the same way that java lets you clone any object but just marking it clonable. – Chris Marisic Jun 09 '11 at 16:37
  • 1
    Some explanation of why you need a deep copy would be helpful. – Adam Robinson Jun 09 '11 at 16:40
  • @Chris: Copying the memory of an object would, by definition, be a *shallow* copy. A deep copy requires traversing all object references and is just begging for trouble. I don't see a need for introducing a language- or runtime-level capability for performing deep copies. – Adam Robinson Jun 09 '11 at 16:41
  • @Adam Robinson I'm talking the entire memory block(s) that physically contains the WHOLE object. Not the memory address of the pointer... And if you don't feel there needs to be a deep copy clearly you've never wrote code that works with deep lists that requires you to clone the list, and mutate it without disturbing the original list... – Chris Marisic Jun 09 '11 at 16:46
  • 4
    @Chris - There isn't a 'block' which contains a 'whole' object, other than in the shallow-copy sense. – Will Dean Jun 09 '11 at 16:49
  • @Chris: As @Will says, there is no contiguous block of memory that contains a "whole" object (in the deep copy sense; this is also true of Java). You're right that I haven't written code that "works with deep lists that requires you to clone the list, and mutate it without disturbing the original list", as that's not a very OO way of doing things. – Adam Robinson Jun 09 '11 at 17:11
  • What does it matter if it's contiguous or not? .NET knows where the entire object is, it what does it matter if it has to copy 1 block, or 50 blocks? – Chris Marisic Jun 09 '11 at 18:02
  • @smartcaveman - I had not heard of that, interesting. Its only supported in .NET 4 however and I am using 3.5 in order to utilise a compatible library. – marked Jun 10 '11 at 08:47
  • @Adam - I am using a custom class containing a dictionary to maintain a list of the parameters I am reading, if they change I update a database. I need a deep copy in order to store the last know values and reassign the current vales to last known once they are updated. 'previous = current' after the update kind of thing. Without a deep copy I would constantly compare the same list of parameters. – marked Jun 10 '11 at 08:50
  • 1
    @Marked, if you are new to C#, I highly recommend reading CLR via C# by Jeffrey Richter (http://www.amazon.com/CLR-via-C-Jeffrey-Richter/dp/0735627045). He used the deep copy via serialization method found in the other post. – Jason Jun 10 '11 at 12:46

2 Answers2

3

Based upon follow up responses in the comments, the best solution to what you're looking for is the simplest one: write the code to copy the object yourself.

If your class is really as simple as a wrapper around a dictionary that stores key/value pairs for custom properties, you can use the Dictionary(IDictionary) constructor to copy the values from one dictionary to another.

class MyWrapper
{
    private Dictionary<string, object> properties = 
                                         new Dictionary<string, object>();

    public MyWrapper Clone()
    {
        MyWrapper output = new MyWrapper();

        output.properties = new Dictionary<string, object>(properties);
    }
}

Obviously, this is a simplified class that doesn't actually do anything, but from what you've described this should get you what you need. No reflection, no "gotchas", just a simple copy of values from one dictionary to another.

EDIT

I can't speak to mono portability, as I'm a Windows-only developer, but as for efficiency, an explicit solution where you copy what you need will be a hands-down winner over a reflection-based solution.

The concept of a true deep copy of any arbitrary type is not something easily (or even safely) achieved in a reference-based object-oriented language. While simple classes would be trivial to copy, reference loops, classes without parameterless constructors, and immutable types present challenges.

For instance, consider this class:

public class Foo
{
    public Foo Next { get; set; }
}

Which is pretty much the simplest implementation of a singly-linked list. A naive deep copy algorithm would start at the first instance of Foo, then clone it by recursively navigating down the chain of Next references until it encountered a null value. However, doing this, we'll not only eat up memory but also end up with objects that do not represent an actual clone of the original:

Foo first = new Foo();

first.Next = new Foo();

first.Next.Next = first;

This is a perfectly legal (and even reasonable) thing to do, but now we have a circular reference loop that will blow up our naive cloning algorithm. So now we have to implement an object cache.

Dictionary<object, object> clonedObjects;

Now, in the clone algorithm, when assigning values to properties or fields, we check the cache to see if the reference we're about to duplicate has already been cloned. If it has, we use that value instead of cloning a new one. This will give us a brand new object graph that represents our original object and is also a complete clone. Great, right?

Now, what about parameterless constructors? This one isn't even solvable in a completely generic sense. If I create this class:

public class Bar
{
    public Bar(string gotcha) { }
}

There's no way to clone this class in a naive sense; since you have no way of knowing how to call the constructor (you can obtain the ConstructorInfo reflectively, but the semantics of how it's called will be completely unknown. The best you could do would be to store metadata (by way of a custom attribute on the class) about which constructor to call and how to call it (a list of fields in the order that they should be passed, for example), but that requires previous knowledge of the cloning mechanism and also implies that the arguments for the constructor are fields on the original object, which is not necessarily the case.

Now we throw another snag into the mix: immutable reference types. This one can also potentially result in unexpected behavior. Immutable reference types are reference types whose (externally visible) value cannot change; in most cases, these classes are designed to exhibit value-type semantics. They also frequently lack parameterless constructors (and may not even have a publicly-accessible constructors at all), making them suffer from our previous irritation, but they may also use a factory-based method so that they can ensure that referential equality also means value equality, and vice versa (this latter condition is less common, but if we're talking about an algorithm that is a totally naive cloning mechanism, then we have to cover it). This, again, means another custom attribute to indicate that the cloning mechanism should simply copy the reference rather than cloning the actual object.

So, in short, a completely naive deep copy mechanism simply isn't possible when dealing with arbitrary types. Types would have to be designed with the cloning mechanism in mind, and may have to make concessions or decorate themselves in a particular way in order to work with it. This, combined with the relatively infrequent requirement, is likely why there is no framework-level deep copy mechanism now, and why you should consider a more explicit copying mechanism where you know what to copy (and what may not matter) so that you can be certain that what you get is what you want.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • This seems like a good solution, however I accepted the deepClone method as I had implemented and it worked well. Also, there was more information on the struct. However, no one answered in relation to efficiency or mono portability :/ – marked Jun 16 '11 at 15:05
  • @marked: Please see my edit. Apologies for the length, but even if it doesn't change your approach, it's something you should keep in mind. – Adam Robinson Jun 16 '11 at 15:35
  • It seems I had to revisit this and go with your solution, as the serialisation was not portable (at least without considerable work). Your solution is simple and effective and works well, cheers! The detailed explanation is also appreciated! – marked Jul 26 '11 at 09:07
1

Structs have some unique characteristics that should be heavily considered before using them.

  • They all are values types (this will add challenges to passing them around)
  • They all take up memory on the stack instead of the heap
  • they must have parameterless constructors
  • no inheritance for structs

http://msdn.microsoft.com/en-us/library/aa288471(v=vs.71).aspx

Take those points into consideration before asking whether or not structs are a viable option for your situation.

I generally would stick with just writing a method for my class the creates a deep copy. You could probably get real fancy and use a combination of generics and reflection to write a pretty abstract DeepClone<T>(T object) sort of method. Or take the easy road and just write one tailor fitted to the class in question.

Matthew Cox
  • 13,566
  • 9
  • 54
  • 72
  • @Matthew Cox You had me until reflection.. =( – Yuck Jun 09 '11 at 16:49
  • @Yuck lol I wasn't down for it either. I was just pointing out options. =P – Matthew Cox Jun 09 '11 at 16:50
  • @Yuck It's unfortunate that .NET doesn't have a solid mechanism for cloning objects. Now I am no expert but, attempting to create a magic method that would clone any class would seem to require reflection. Things like attributes couldn't be cloned AFAIK without the use of reflection (for example). I have been wrong from time to time though =P – Matthew Cox Jun 09 '11 at 16:55
  • "stack instead of the heap" - I encourage you to read [the truth about value types](http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx). – Anthony Pegram Jun 09 '11 at 16:58
  • 1
    @Anthony Pegram The article link I posted from the MSDN candidly states the following: "However, when you instantiate a struct, it gets created on the stack. ..." If this was the reason for your down vote. Then I would encourage you to reconsider. – Matthew Cox Jun 09 '11 at 16:59
  • 2
    @Matthew: That article is, unfortunately, overly simplistic. I would suggest reading Eric Lippert's article, which @Anthony linked to. – Adam Robinson Jun 09 '11 at 17:18
  • @Matthew Cox: I really hate that terminology. The correct thing would be to say that a variable or field of a value type stores information in the variable or field, while one of a reference type stores within the variable or field a reference to information which is stored elsewhere, on the heap. Variables are stored on the stack; fields within a reference types are stored on the heap. Fields within a value type will be stored in the same location as the value type itself. – supercat Jun 09 '11 at 17:49