Extension methods for copying or cloning objects
C# 3.0 includes a new feature known as extension methods, and fiddling with it triggered the idea of creating a mechanism for copying or cloning (virtually) any .NET object or graph of objects. The manifestation of that idea has become a rather decent little framework for copying objects. It performs a deep copy as automatically as it possibly can, and provides mechanisms to easily solve many of the cases which cannot be covered automatically. It is great for copying your custom object hierarchies, and saves you the pain of a solution like implementing ICloneable for an entire hierarchy of objects. Click here to grab it now, and read on for a presentation.
Let’s start off with a few words on extension methods. They are best explained through an example. Let’s say we want to be able to calculate area given size. Wouldn’t it be nice to be able to add GetArea to the already existing Size class? Well, let’s do so!
- public static class ExtensionMethods
- {
- public static int GetArea(this Size size)
- {
- return size.Width * size.Height;
- }
- }
As you can see, the new syntax simply allows you to tell the compiler that the this of this method is a Size. This means that the method is an extension of the Size class.
As mentioned, I had the idea of extending the very base of the C# class hierarchy (System.Object) with a method for copying or cloning “any” object. Obviously, the method cannot automatically copy any object, since it cannot possibly know how to construct an object from an arbitrary class. Hence, a small framework needed to be created. The goals were to:
- Enable copying of many objects automatically.
- Enable copying of virtually any object with very little effort.
- Automate and hide away as much as possible (The KISS Principle).
The result is Copyable (pun intended).
The Copyable framework
Copyable is a small framework for copying (or cloning, if you will) objects. The straightforward way of using it is to just reference the assembly it’s in from your project, and start copying!
- // …do lots of stuff to the object…
- SomeType copy = instance.Copy(); // Create a deep copy
The instance copy is now a deep copy of instance, no matter how complex the object graph for instance is. The relations in the copy graph is the same as in instance, but all objects in the copy object graph are copies of those in instance.
For the automated copy to work, though, one of the following statements must hold for instance:
- Its type must have a parameterless constructor, or
- It must be a
Copyable, or - It must have an
IInstanceProviderregistered for its type.
Besides the Copy method, The Copyable class and IInstanceProvider interface are the two major building blocks of the Copyable framework. Each of these blocks enable copying of objects that cannot automatically be copied.
The Copyable base class
Copyable is an abstract base class for objects that can be copied. To create a copyable class, you simply subclass Copyable and call its constructor with the arguments of your constructor.
- class MyClass : Copyable
- {
- public MyClass(int a, double b, string c)
- : base(a, b, c)
- {
- }
- }
This code above makes MyClass a copyable class. Note that if MyClass had had a parameterless constructor, subclassing Copyable would not be necessary.
MyClass can now be copied just like the previous example.
- MyClass b = a.Copy();
The introduction of the Copyable base class solves many problems, but not all. Let’s say you wanted to copy a System.Drawing.SolidBrush. This class does not have a parameterless constructor, which means it cannot be copied “automatically” by the framework. Also, you cannot alter it so that it subclasses Copyable. So, what do you do? You create an instance provider.
The IInstanceProvider interface
An instance provider is defined by the interface IInstanceProvider. As the name clearly states, the implementation is a provider of instances. One instance provider can provide instances of one given type. The Copyable framework automatically detects IInstanceProvider implementations in all assembies in its application domain, so all you need to do to create a working instance provider is to define it. No registration or other additional operations are required. To simplify the implementation of instance providers and the IInstanceProvider interface, an abstract class InstanceProvider is included in the framework.
- public class SolidBrushProvider
- : InstanceProvider<SolidBrush>
- {
- public override SolidBrush CreateTypedCopy(SolidBrush s)
- {
- }
- }
This implementation will be used automatically by the Copyable framework. NOTE: To be usable, the instance provider MUST have a parameterless constructor.
The instance provider pattern does not solve the case where you want different initial states for your SolidBrush instances depending on which context you use them for copying. For those cases, an overload of Copy() exists which takes an already created instance as an argument. This argument will become the copy.
- instance.Color = Color.Black;
- instance.Copy(copy); // Create a deep copy
In this example, copy is now of the color Color.Black.
Limitations and pitfalls
Although this solution works in most cases, it’s not a silver bullet. Be aware when you copy classes that hold unmanaged resources such as handles. If these classes are designed on the premise that their resources are exclusive to them, they will manage them as they see fit. Imagine if you copied a class which holds a handle, disposed one of the instances, and continued using the copy. The handle will (probably) be freed by the original instance, and the copy will generate an access violation by attempting reading or writing freed memory.
That’s it! The Copyable framework can be downloaded from here. For those interested in reading more on extension methods, For additional information, MSDN provides an excellent explanation in the C# Programming Guide, and Scott Guthrie has an introduction article here.
Enjoy Copyable, and please let me know if you find it useful or come across any problems with it.
UPDATE 2009-12-11: Due to popular demand, I have made the source code for Copyable available under the MIT license. The source can be downloaded here.
UPDATE 2010-01-31: The requirement of parameterless constructors has been removed in the latest version of Copyable available on GitHug. A new release will follow soon.
























Leonardo Cooper said
on May 5 2008 at 22:42
you are my hero, thanks a lot… just of problem though, declaring an event in the instance to be copied throws an exception because seens delegates dont have parameterless ctors.
Håvard said
on May 14 2008 at 17:41
Leonardo: Create an IInstanceProvider implementation for it, to provide the Copyable framework with instances.
C# Object Clone Wars : C# 411 said
on May 22 2008 at 16:56
[...] Stranden created a custom cloning framework using extension methods. The framework creates a deep copy of an object and all referenced [...]
Håvard said
on May 26 2008 at 23:20
After numerous requests, I have decided to make the source code available. It is released under the MIT license, and can be downloaded from here.
FP said
on June 13 2008 at 14:56
How about this:
public interface IInstanceProvider : IInstanceProvider where T: new()
Thanks
Jeff said
on August 19 2008 at 18:56
Exactly what I was looking for. Thanks!
barry said
on May 13 2009 at 23:05
I have a class with a generic event handler (EventHandler).
I created a class the implements InstanceProvider for EventHandler but I still get “object of type {0} cannot be cloned…” when trying to clone the System.Reflection.RuntimeMethodInfo from the event handler.
Has anyone gotten this to work?
Thanks.
Ron Klein said
on July 13 2009 at 09:06
Nice! Please take a look at your code snippet in the “The IInstanceProvider interface” section, I think you should use override keyword there.
Håvard said
on July 13 2009 at 13:50
Ron: You are indeed right, thanks for spotting! Example updated now.
Walter Oesch said
on September 16 2009 at 11:51
Hello Havard
Great Work Havard. Copying entire Object graphs is very important for me. Recently i had problems copying an object graph in which a child object has a reference to the parant object. This caused copying to crash. It crashed in private static object Clone(this object instance, VisitedGraph visited, object copy) { visited.Add(instance, copy); … }
I changed the implementation to private static object Clone(this object instance, VisitedGraph visited, object copy) if(!visited.ContainsKey(instance)) { visited.Add(instance, copy); }
and then it worked. Is this a safe change or is it in general not possible to copy graphs which have back references?
Håvard said
on September 16 2009 at 12:48
Hi Walter,
Glad to hear Copyable is useful for you. What you have found is a bug in Copyable. The change you have made should be:
Replace line 135 of ObjectExtensions.cs:
With these lines:
This ensures that the copy is returned if the instance has already been visited.
I will make a fix and a new version of Copyable available soon. Thanks for noticing and notifying!
EDIT: Updated the code I provided here. The else clause was missing, bug was spotted by Sergey (comment below).
Mark said
on September 21 2009 at 10:00
Would using FormatterServices.GetUninitializedObject() allow automatic cloning of objects without a default constructor?
Håvard said
on September 22 2009 at 08:51
Mark: It would. I am considering patching Copyable so that it uses FormatterServices.GetUninitializedObject instead of Activator.CreateInstance, but haven’t gotten around to it yet. Copyable needs a revamp, polish, and new release anyway, so I’ll hopefully get it done soon. Feel free to submit a patch!
Sergey said
on September 28 2009 at 08:25
I replaced
line 135 of ObjectExtensions.cs: visited.Add(instance, copy); With these two lines:
if(visited.ContainsKey(instance)) return visited[instance]; as You said and got a bug in TestCyclicObjectHierarchyClone test.
Alex said
on December 10 2009 at 01:50
Hi Håvard,
I just stumbled over this blog post and intended to use your extensions. The only problem I ran into was that I mainly use auto-properties and, from what I see in the source, you only read out the fields, so my properties are not cloned unfortunately.
Is there a particular reason you haven’t implemented that? Can you give me a nudge to what I could to to extend the extension to support properties as well?
Greetings Alex
PS: And totally OT… Håvard… I just looked it up on Wiki only getting nowegian or icelandish results. And as my swedish is limited (and I don’t know much about the icelandish characters) I don’t understand where it comes from. I’m just interested
Thanks!
Alex said
on December 10 2009 at 03:04
Hi Håvard,
sorry for double posting. I just found the solution.
It wasn’t at all about the properties. Obviously at runtime there are the backing fields. I haven’t thought about them. My Bad. Anyway, this didn’t resolve my issue. So I had to see, where exactly lies the problem. –> Inheritance! Obviously a backing field is private… So I can’t get the values of the base class as it can’t be seen.
So I added a little to one of the private Copy Methods to support base types. I added a little loop to loop through all base types and get the values from there.
Here is the edited Method, in case you want to add this. Do what ever you want with it
Greetings
Alex
Method:
Alex said
on December 10 2009 at 03:18
As we say in germany “Alle guten Dinge sind 3″ (All good things are three). Here my 3rd Post
And actually the most important.
Thank you for the work you have done with this, Håvard! It is actually very useful for me!
Håvard said
on December 10 2009 at 09:57
Hi Alex,
Glad to hear you found your problem and solved it! I will incorporate your findings into Copyable as soon as I find time to do it.
As for my name, it’s basically the Norwegian version of the English Howard, which means something like “Noble Watchman”. The å is the 29th and final character in the Norwegian alphabet, and its pronounciation is like the German way to say “o” in words like “oma”. Also, the d in the end is mute.
Alex said
on December 10 2009 at 11:46
Hi Håvard,
first of all, I know about the å.
As I said, I know a little swedish brag (At least I understand quite a bit).
The problem in itself was that Wiki said this: Hávarðr. I know it’s icelandish, but that’s all
.
And another quite off topic question. Yesterday, while researching your name, I had a discussion with my girlfriend as to what is actually the spoken language in norway, as there are (as much as I understand) two versions: bokmål and nynorsk. Though my bet was on nynorsk.
About Topic. Hey, that’s great that my change gets into your code. I’m honored. Actually, the first contribution I could to so far xD. And what do you think, I use that merely to achieve a Copy & Paste effect. But hey, it works like a charm
Greetings Alex
Håvard said
on December 10 2009 at 13:24
More off-topic replies:
Icelandish and old Norwegian are very similar languages, so you’ve probably hit a wiki with information on old Norwegian/icelandic names. Icelandic and old Norwegian were the same language a long time ago, and Iceland was actually part of Norway until the beginning of the 20th century.
Bokmål and nynorsk are the two written languages in Norway. Bokmål is the most common, and all Norwegians must learn both written languages. Ironically, nobody in Norway actually speaks neither bokmål nor nynorsk. Norway has a ton of very different dialects, of which many are close too (but not quite the same as) bokmål or nynorsk, and some are quite different from both.
Again great to hear that you find Copyable useful. Many do, and so I think it’s time to establish a “project” for it and allow people to contribute their changes.
Alex said
on December 10 2009 at 16:10
Do you mean making it open source?
Håvard said
on December 10 2009 at 16:17
It is already open source (released under the MIT license, and you just changed the code, remember?
), but I’m moving it to make it more readily available for accepting work from others. Git is a great tool for this. People can pull Copyable, alter it, and submit patches to me for inclusion in the master branch.
Alex said
on December 10 2009 at 16:27
Ahh. Sorry, I expressed myself incorrecly. Open Source it is already. I meant like creating a Project at.. say SourceForge or whatever.
Brian said
on January 8 2010 at 21:44
How is the performance of this compared to other techniquest (manually copying, serialize/deserialize, etc)? I’m looking for a way to quickly clone a very large and complex object and performance is critical.
Håvard said
on January 15 2010 at 15:08
Brian: If performance is truly CRITICAL, then Copyable is probably not for you. It uses reflection for copying, which introduces an overhead (albeit small).
Bear in mind, however, that time is money, and money rules the world, and Copyable will make your graph clone in one line of code which takes you about 10 seconds to write. A custom optimized copy routine will likely take days or weeks provided that the graph is relatively complex.
Good luck!
John Cheng said
on January 31 2010 at 01:30
Recently I did some similar work. I like the convenient provided by the OX.Copyable library. But I think the first limitation of “must have a parameterless constructor” can be avoided by taking the advantage of MemberwiseClone function. The idea is that regardless the member structure of an object; I can create a shallow copy of any object by using the MemberwiseClone function. Then, I can walk through the reference members of the new copy and replace them with a deep copy. I tried this technical on top of the source code of OX.Copyable. It passed all the existing testing cases. The only change I made was to replace the DeduceInstance function with the following code:
Håvard said
on January 31 2010 at 02:04
John: The latest version of Copyable on GitHub does not require parameterless constructors. The blog post has now been updated to reflect this.
I’d still like to test your patch. Are you able to pull from the GitHub repository, create a patch, and make it available so I can pull it into a branch of Copyable?
John Cheng said
on February 2 2010 at 00:15
Håvard, It seems I don’t have the write permission to your code. But I was able to get the latest code and try my change on it. My patch passed all tests except the one that tests provider usage: Assert.IsTrue(SolidBrushProvider.NumCalls > 0); This failure is expected, since my patch does not require or use any provider. Isn’t this another advantage! Let me know if I can add my patch, or you may add it for me.
Håvard said
on February 2 2010 at 09:19
John, that’s right, you don’t have write access. You need to prepare and send a “pull request” through GitHub (see the GitHub docs).
Patches with failing tests will not be accepted.
The instance provider mechanism is still useful for objects with unmanaged resources, so it will stay alive in spite of a new way of cloning.
Ilya said
on February 9 2010 at 21:05
Thanks very helpful, liked the code!!
Ben said
on February 11 2010 at 06:59
Error in Cloning one of my object
Exception Details: System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Source Error:
Line 57: private static IEnumerable GetInstanceProviders(Assembly assembly) Line 58: { Line 59: foreach (Type t in assembly.GetTypes()) Line 60: { Line 61: if (typeof(IInstanceProvider).IsAssignableFrom(t))
Håvard said
on February 11 2010 at 09:13
Ben: I am going to need a source code copy that reproduces this problem. You can send me a copy at havard DOT stranden ATT gmail DOT com.
Boris Modylevsky said
on February 16 2010 at 14:14
Thanks for writing such a framework!
I managed easily incorporate it into my code due to the use of extensions. But I had two issues with this:
While using in Debug, it throws, catches and ignores exceptions in GetInstanceProviders method. It would be nice to remove throwing in terms of performance and convenience in Debug.
Copy() method does copy objects properties, but does not copies inherited properties. Take a look at this piece of code:
public class Mammal { public Guid Id { get; set; } }
public class Human : Mammal { // The rest of Human class as defined in Human.cs }
// Add the following line // in TestCloneHumanInOtherAssembly test and it fails Assert.AreEqual(father.Id, sensation.Id);
Håvard said
on February 16 2010 at 14:19
Boris: Thanks for sharing! The issue with inherited properties has been reported earlier, and is fixed in the latest version of Copyable on GitHub . You can get a copy of the source there.
As for the issue of exceptions, I’ll see if I can find time to lessen the exception throwing for added debugging convenience. Until then, rest assured that they are handled properly.
Boris Modylevsky said
on February 17 2010 at 10:07
Håvard, thanks for the quick reply. Copyable framework downloaded from GitHub does contain support for inherited properties and it works well. BUT, I was trying to use this framework in Silverlight and it fails on build with the following error:
‘System.AssemblyLoadEventArgs’ is inaccessible due to its protection level. File: ObjectExtensions.cs Line : 24
Here are my steps to create a Silverlight compatible Copyable framework: 1. Create a new Silverlight Class Library project, named OX.Copyable.Silverlight 2. Add existing files as links from OX.Copyable project to the new created one. Make sure you’re adding them as links. 3. Build
Thanks in advance!
Rachel T said
on February 19 2010 at 14:01
Tried the suggestion (yes, the files were linked into a new SL class lib proj) for making this work in Silverlight 3 and still throws the same error when trying to compile the wrapper project that I created. Has anyone besides Boris been able to make this work for Silverlight 3?
Håvard said
on February 19 2010 at 14:57
Rachel: Sadly, OX.Copyable won’t easily work with Silverlight. There are several issues that need to be adressed before a Silverlight version can be built. I hope to be able to research the possibilities for Silverlight support in the near future. Keep watching!