|
1 | 1 | # DeepCloner |
| 2 | +=============== |
2 | 3 |
|
3 | | -In progress... |
| 4 | +Library with extenstion to clone objects for .NET. It can deep or shallow copy object. In deep cloning all object graph is maintained. Library using code-generation in runtime as result object cloning is really fast. |
| 5 | +Objects are copied by its' internal structure, **no** methods or constructuctors are called for cloning objects. As result, you can copy **any** object, but we don't recommend to copy objects which are binded to native resources or pointers. It can cause unpredictable results (but object will be cloned). |
| 6 | + |
| 7 | +You don't need to mark objects somehow, like Serializable-attribute, or restrict to specific interface. Absolutely any object can be cloned by this library. And this object doesn't have any ability to determine that he is clone (except very specific methods). |
| 8 | + |
| 9 | +## Limitation |
| 10 | + |
| 11 | +**Library requires full trust permission set!** Usually, it is not a problem, but in case of such restriction, you should use another library, e.g. [CloneExtensions](https://github.com/MarcinJuraszek/CloneExtensions). It clones only public properties of objects, so, result can differ, but it works anywhere. |
| 12 | + |
| 13 | +## Usage |
| 14 | + |
| 15 | +Deep cloning any object: |
| 16 | +``` |
| 17 | + var clone = new { Id = 1, Name = "222" }.DeepClone(); |
| 18 | +``` |
| 19 | + |
| 20 | +With a reference to same object: |
| 21 | +``` |
| 22 | + // public class Tree { public Tree ParentTree; } |
| 23 | + var t = new Tree(); |
| 24 | + t.ParentTree = t; |
| 25 | + var cloned = t.DeepClone(); |
| 26 | + Console.WriteLine(cloned.ParentTree == cloned); // True |
| 27 | +``` |
| 28 | + |
| 29 | +Or as object: |
| 30 | +``` |
| 31 | + var date = DateTime.Now; |
| 32 | + var object = (object)date; |
| 33 | + object.DeepClone().GetType(); // DateTime |
| 34 | +``` |
| 35 | + |
| 36 | +Shallow cloning (clone only same object, not objects that object relate to) |
| 37 | +``` |
| 38 | + var clone = new { Id = 1, Name = "222" }.ShallowClone(); |
| 39 | +``` |
| 40 | + |
| 41 | +## Installation |
| 42 | + |
| 43 | +Trought nuget: |
| 44 | +``` |
| 45 | + Install-Package DeepCloner |
| 46 | +``` |
| 47 | + |
| 48 | +## Details |
| 49 | + |
| 50 | +You can use deep clone of objects for a lot of situations, e.g.: |
| 51 | +* Emulation of external service or _deserialization elimination_ (e.g. in Unit Testing). When code has received object from external source, code can change it (because object for code is *own*). |
| 52 | +* ReadOnly object replace. Instead of wrapping your object to readonly object, you can clone object and target code can do anything with it without any restriction. |
| 53 | +* Caching. You can cache data locally and want to ensurce that cached object hadntt been changed by other code |
| 54 | + |
| 55 | +You can use shallow clone as fast, light version of deep clone (if your situation allows that). Main difference between deep and shallow clone in code below: |
| 56 | +``` |
| 57 | + // public class A { public B B; } |
| 58 | + // public class B { public int X; } |
| 59 | + var b = new B { X = 1 }; |
| 60 | + var a = new A { B = b }; |
| 61 | + var deepClone = a.DeepClone(); |
| 62 | + deepClone.B.X = 2; |
| 63 | + Console.WriteLine(a.B.X); // 1 |
| 64 | + var shallowClone = a.ShallowClone(); |
| 65 | + shallowClone.B.X = 2; |
| 66 | + Console.WriteLine(a.B.X); // 2 |
| 67 | +``` |
| 68 | +So, deep cloning is guarantee that all changes of cloned object does not affect original. Shallow clone does not guarantee this. But it faster, because deep clone of object can copy big graph of related objects and related objects of related objects and related related related objects, and... so on... |
| 69 | + |
| 70 | +This library does not call any method of cloning object: constructors, Equals, GetHashCode, propertes - nothing is called. So, it is impossible for cloning object to receive information about cloning, throw an exception or return invalid data. |
| 71 | +If you need to call some methods after cloning, you can wrap cloning call to another method which will perform required actions. |
| 72 | + |
| 73 | +Extension methods in library are generic, but it is not require to specifify type for cloning. You can cast your objects to System.Object, or to an interface, add fields will be carefully copied to new object. |
| 74 | + |
| 75 | +### Performance |
| 76 | +Cloning Speed can vary on many factors. This library contains some optimizations, e.g. structs are just copied, arrays also can be copied through Array.Copy if possible. So, real performance will depend on structure of your object. |
| 77 | + |
| 78 | +Tables below, just for information. Simple object with some fields ara cloned multiple times. Preparation time (only affect first execution) excluded from tests. |
| 79 | + |
| 80 | +**Deep cloning** |
| 81 | + |
| 82 | + Method | Time (in ms) | Comments |
| 83 | +---|---|--- |
| 84 | +Manual | 11 | You should manually realize cloning. It requires a lot of work and can cause copy-paste errors, but it is fastest variant |
| 85 | +DeepClone | 200 | This variant is 20 times slower than manual, but clones any object without preparation |
| 86 | +[CloneExtensions](https://github.com/MarcinJuraszek/CloneExtensions) | 400ms | Implementation of cloning objects on expression trees. |
| 87 | +BinaryFormatter | 10000 | Another way of deep object cloning through serializing/deserializing object. Instead of Json serializers - it maintains full graph of serializing objects and also do not call any method for cloning object. But due serious overhead, this variant is very slow |
| 88 | + |
| 89 | +**Shallow cloning** |
| 90 | +Shallow cloning is usually faster, because we no need to calculate references and clone additional objects. |
| 91 | + |
| 92 | + Method | Time (in ms) | Comments |
| 93 | +---|---|--- |
| 94 | +Manual | 11 | You should manually realize clone, property by property, field by field. Fastest variant |
| 95 | +Manual / MemberwiseClone | 37 | Fast variant to clone: call MemberwiseClone inside your class. Should be done manually, but does not require a lot of work. |
| 96 | +ShallowClone | 48 | Slightly slower than MemberwiseClone due checks for nulls and object types |
| 97 | +[CloneExtensions](https://github.com/MarcinJuraszek/CloneExtensions) | 120 | Implementation of cloning objects on expression trees. |
| 98 | + |
| 99 | +## License |
| 100 | + |
| 101 | +[MIT](https://github.com/force-net/DeepCloner/blob/develop/LICENSE) license |
0 commit comments