* By default, if a class has DataContract or CollectionDataContract attributes, then only members with the DataMember attribute are translated to the snapshot; otherwise, all fields and properties of the class are public or not.
var snapshot0 = instance0.CreateSnapshot(); /* use default ReplicationProfile */ var customReplicationProfile = new ReplicationProfile { MemberProviders = new List<MemberProvider> { //new MyCustomMemberProvider(), /* you may override and customize MemberProvider class! */ new CoreMemberProviderForKeyValuePair(), //new CoreMemberProvider(BindingFlags.Public | BindingFlags.Instance, Member.CanReadWrite), new ContractMemberProvider(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, Member.CanReadWrite) } }; var snapshot1 = instance1.CreateSnapshot(customReplicationProfile ); Snapshot.DefaultReplicationProfile = customReplicationProfile;
var cache = new Dictionary<object, int>(); var snapshot0 = graph0.CreateSnapshot(cache); /* modify 'graph0' by any way */ var graphX = snapshot0.ReconstructGraph(cache); /* graphX is the same reference that graph0, all items of the graph reverted to the previous state */
* It should be remembered that cached objects are kept from garbage collection, and during the reconstruction all of them return to their original state.
var snapshot0 = graph0.CreateSnapshot(cache); /* modify 'graph0' by any way */ var graph1 = snapshot0.ReplicateGraph(cache); /* graph1 is a deep copy of the source graph0 */
Copying is of two types - superficial and deep. Let objects A and B be given, moreover, A contains a reference to B (column A => B). At the surface copying of object A, object A 'will be created, which will also refer to B, that is, in the end, we get two columns A => B and A' => B. They will have a common part B, so when changing object B in the first column, its state will automatically mutate in the second one. Objects A and A 'will remain independent. But the most interesting are the graphs with closed (cyclic) links. Let A refer to B and B refer to A (A <=> B), when copying object A to A, we get a very unusual graph A '=> B <=> A, that is, the original object got into the final graph subjected to cloning. Deep copying involves the cloning of all objects included in the graph. For our case, A <=> B is converted to A '<=> B', as a result, both graphs are completely isolated from each other. In some cases, superficial copying is sufficient, but not always.
var snapshot0 = instance0.CreateSnapshot(); /* etalon */ var snapshot1 = instance1.CreateSnapshot(); /* sample */ var juxtapositions = snapshot0.Juxtapose(snapshot1).ToList(); var differences = juxtapositions.Where(j=>j.State == Etalon.State.Different);
* Importantly, the result of the mapping operation is IEnumerable<Juxtaposition>
, which makes it possible to interrupt the recursive mapping process at any time after certain conditions are reached, rather than producing it completely, which in turn is significant for performance.
using System; using System.Collections.Generic; using System.Runtime.Serialization; namespace Art.Replication.Diagnostics { [DataContract] public class Role { [DataMember] public string Name; public string CodePhrase; [DataMember] public DateTime LastOnline = DateTime.Now; [DataMember] public Person Person; } public class Person { public string FirstName; public string LastName; public DateTime Birthday; public List<Role> Roles = new List<Role>(); } public static class DiagnosticsGraph { public static Person Create() { var person0 = new Person { FirstName = "Keanu", LastName = "Reeves", Birthday = new DateTime(1964, 9 ,2) }; var roleA0 = new Role { Name = "Neo", CodePhrase = "The Matrix has you...", LastOnline = DateTime.Now, Person = person0 }; var roleB0 = new Role { Name = "Thomas Anderson", CodePhrase = "Follow the White Rabbit.", LastOnline = DateTime.Now, Person = person0 }; person0.Roles.Add(roleA0); person0.Roles.Add(roleB0); return person0; } } }
using Art; using Art.Replication; using Art.Replication.Replicators; using Art.Replication.MemberProviders; using Art.Serialization; using Art.Serialization.Converters;
public static void CreateAndSerializeSnapshot() { var person0 = DiagnosticsGraph.Create(); var snapshot0 = person0.CreateSnapshot(); string rawSnapsot0 = snapshot0.ToString(); Console.WriteLine(rawSnapsot0); Console.ReadKey(); }
{ #Id: 0, #Type: "Art.Replication.Diagnostics.Person, Art.Replication.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", FirstName: "Keanu", LastName: "Reeves", Birthday: "1964-09-02T00:00:00.0000000+03:00"<DateTime>, Roles: { #Id: 1, #Type: "System.Collections.Generic.List`1[[Art.Replication.Diagnostics.Role, Art.Replication.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", #Set: [ { #Id: 2, #Type: "Art.Replication.Diagnostics.Role, Art.Replication.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", Name: "Neo", LastOnline: "2017-06-14T14:42:44.0000575+03:00"<DateTime>, Person: { #Id: 0 } }, { #Id: 3, #Type: "Art.Replication.Diagnostics.Role, Art.Replication.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", Name: "Thomas Anderson", LastOnline: "2017-06-14T14:42:44.0000575+03:00"<DateTime>, Person: { #Id: 0 } } ] } }
Person: { #Id: 0 }
Birthday: "1964-09-02T00:00:00.0000000+03:00"<DateTime>
. It is necessary to restore (deserialize) the image without distortion. public static void UseClassicalJsonSettings() { Snapshot.DefaultReplicationProfile.AttachId = false; Snapshot.DefaultReplicationProfile.AttachType = false; Snapshot.DefaultReplicationProfile.SimplifySets = true; Snapshot.DefaultReplicationProfile.SimplifyMaps = true; Snapshot.DefaultKeepProfile.SimplexConverter.AppendTypeInfo = false; Snapshot.DefaultKeepProfile.SimplexConverter.Converters .OfType<NumberConverter>().First().AppendSyffixes = false; } public static void CreateAndSerializeSnapshotToClassicJsonStyle() { UseClassicalJsonSettings(); var person0 = DiagnosticsGraph.Create(); var snapshot0 = person0.CreateSnapshot(); string rawSnapsot0 = snapshot0.ToString(); Console.WriteLine(rawSnapsot0); var person0A = rawSnapsot0.ParseSnapshot().ReplicateGraph<Person>(); Console.WriteLine(person0A.FirstName); Console.ReadKey(); }
{ FirstName: "Keanu", LastName: "Reeves", Birthday: "1964-09-02T00:00:00.0000000+03:00", Roles: [ { Name: "Neo", LastOnline: "2017-06-14T18:31:20.0000205+03:00", Person: { #Id: 0 } }, { Name: "Thomas Anderson", LastOnline: "2017-06-14T18:31:20.0000205+03:00", Person: { #Id: 0 } } ] }
public class Distorsion { public object[] AnyObjects = { Guid.NewGuid(), Guid.NewGuid().ToString(), DateTime.Now, DateTime.Now.ToString("O"), 123, 123L, }; }
public static void Replicate() { var person0 = DiagnosticsGraph.Create(); var snapshot0 = person0.CreateSnapshot(); var person1 = snapshot0.ReplicateGraph<Person>(); person1.Roles[1].Name = "Agent Smith"; Console.WriteLine(person0.Roles[1].Name); // old graph value: Thomas Anderson Console.WriteLine(person1.Roles[1].Name); // new graph value: Agent Smith Console.ReadKey(); }
public static void Reconstract() { var person0 = DiagnosticsGraph.Create(); var cache = new Dictionary<object, int>(); var s = person0.CreateSnapshot(cache); Console.WriteLine(person0.Roles[1].Name); // old graph value: Thomas Anderson Console.WriteLine(person0.FirstName); // old graph value: Keanu person0.Roles[1].Name = "Agent Smith"; person0.FirstName = "Zion"; person0.Roles.RemoveAt(0); var person1 = (Person)s.ReconstructGraph(cache); Console.WriteLine(person0.Roles[1].Name); // old graph value: Thomas Anderson Console.WriteLine(person1.Roles[1].Name); // old graph value: Thomas Anderson Console.WriteLine(person0.FirstName); // old graph value: Keanu Console.WriteLine(person1.FirstName); // old graph value: Keanu Console.ReadKey(); // result: person0 & person1 is the same one reconstructed graph }
public static void Justapose() { // set this settings for less details into output Snapshot.DefaultReplicationProfile.AttachId = false; Snapshot.DefaultReplicationProfile.AttachType = false; Snapshot.DefaultReplicationProfile.SimplifySets = true; Snapshot.DefaultReplicationProfile.SimplifyMaps = true; var person0 = DiagnosticsGraph.Create(); var person1 = DiagnosticsGraph.Create(); person0.Roles[1].Name = "Agent Smith"; person0.FirstName = "Zion"; var snapshot0 = person0.CreateSnapshot(); var snapshot1 = person1.CreateSnapshot(); var results = snapshot0.Juxtapose(snapshot1); foreach (var result in results) { Console.WriteLine(result); } Console.ReadKey(); } <Different> [this.FirstName] {Zion} {Keanu} <Identical> [this.LastName] {Reeves} {Reeves} <Identical> [this.Birthday] {9/2/1964 12:00:00 AM} {9/2/1964 12:00:00 AM} <Identical> [this.Roles[0].Name] {Neo} {Neo} <Identical> [this.Roles[0].LastOnline] {6/14/2017 9:34:33 PM} {6/14/2017 9:34:33 PM} <Identical> [this.Roles[0].Person.#Id] {0} {0} <Different> [this.Roles[1].Name] {Agent Smith} {Thomas Anderson} <Identical> [this.Roles[1].LastOnline] {6/14/2017 9:34:33 PM} {6/14/2017 9:34:33 PM} <Identical> [this.Roles[1].Person.#Id] {0} {0}
* Performance comparison was made with BinaryFormatter , Newtonsoft.Json , and also with DataContractJsonSerializer .
Source: https://habr.com/ru/post/330294/
All Articles