Source: own resources, Authors: Agnieszka and Michał Komorowscy
I can bet that you've already heard about and used Auto-Property Initializers and that you love them. At least I do so ;) Here is a small example. In this case an Auto-Property Initializer was used to generate unique identifiers for instances of Entity class. Trivial, isn't it?
public class Entity { public string Guid { get; } = System.Guid.NewGuid().ToString(); /*...*/ }What is important we have guaranteed that a given initializer will be executed only ONCE for an instance of a class. Otherwise it will have no sense! In other words our expectations is that if we create a new instance of Entity class it's identifier will not change. It is generally true, but there are some caveats.
The problem may occur if we use a non-binary serialization in order to serialize and deserialize the same object e.g.: XML or JSON serialization. The difference between binary and non-binary serialization is that the latter creates a completely new object during the deserialization process. Is it bad?
Sometime ago I fixed the following issue. Let's consider a situation where we have a distributed system. Additionally, we keep instances of Entity class in a distributed cache. Each node of this system should be able to retrieve an entity from a cache based on it's identifier. Where is a problem? Each time when someone tries to retrieve an entity from the cache, a new instance with a new identifier will be created. In other words, we'll read from a cache a different object than was put there.
Let's examine Auto-Property Initializers more carefully. They are actually a syntactic sugar and under the hood the compiler generates additional code for us. Let's see what code will be generated for Guid property:
public class Entity { [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly string <guid>__BackingField; public string Guid { get { return this.There is no magic here, Guid property is initialized in a constructor. Now, it should be obvious why a new identifier is generated when a new instance is created by the non-binary deserialization. A solution is to generate identifiers outside of Enity class i.e. do not use Auto-Property Initializer.__BackingField; } } public A() { this.<guid>__BackingField = System.Guid.NewGuid().ToString(); } }
Of course, we don't have to use Auto-Property Initializers to have this problem. However, I think that with Auto-Property Initializers it's easier to make this kind of a mistake.
0 comments:
Post a Comment