I code in C# within the Unity environment (I really like the co-routine mechanism and the yield return
instruction).
At one point, I developed a set of base classes to provide a default behavior to entities that must be exchanged on the wire and cached on the device. And I used generic/template classes to be able to generate instances of the final classes from within the methods of the super class. Information saved on the device are signed with a piece of information obtained from the server.
public class LocalCache<T> where T : BaseModel { public static string signatureKey { get; set; } public T Get(long id) { // Get the JSON from PlayerPrefs // Verify its signature return (T) Activator.CreateInstance(typeof(T), new object[] { JSON }); } public void Save(T entity) { // Get the JSON representing the data // Sign the JSON // Save the signed JSON into PlayerPrefs } public void Reset(long id) { ... } private string SignData(string data) { ... } }
In Java, there would be only one instance of the signatureKey
variable per JVM, whatever the number of class instances. In C#, I've been surprised to find that this attribute is not unique!
public class LocalCache<T> where T : BaseModel { // Other code as shown above... public static void TestDifferentInstanciations() { LocalCache<System.Int64>.signatureKey = "Set for Int64"; UnityEngine.Debug.Log("Int16: " + LocalCache<System.Int16>.signatureKey); // => produces: Int16: UnityEngine.Debug.Log("Int16: " + LocalCache<System.Int64>.signatureKey); // => produces: Int64: Set for Int64 UnityEngine.Debug.Log("string: " + LocalCache<System.string>.signatureKey); // => produces: string: } }
My surprise comes from the fact that the concept of generic class only exist for the definitions. At runtime in C# only exist types and the type of LocalCache<Int16>
is different from the type of LocalCache<Int64>
. Then there are multiple copies of the signatureKey
attribute, exactly one per constructed types...
The solution is to set the singleton into a separated non generic class!
internal static class StaticLocalCacheInfo { public static string signatureKey { get; set; } } public class LocalCache<T> where T : BaseModel { public static string signaturePartFromServer { get { return StaticLocalCacheInfo.signatureKey; } set { StaticLocalCacheInfo.signatureKey = value; } } // Rest of the business logic... public static void TestDifferentInstanciations() { LocalCache<System.Int64>.signatureKey = "Set for Int64"; UnityEngine.Debug.Log("Int16: " + LocalCache<System.Int16>.signatureKey); // => produces: Int16: Set for Int64 UnityEngine.Debug.Log("Int16: " + LocalCache<System.Int64>.signatureKey); // => produces: Int64: Set for Int64 UnityEngine.Debug.Log("string: " + LocalCache<System.string>.signatureKey); // => produces: string: Set for Int64 } }
Note that I got the confirmation of the behavior on Unity forum.
I hope it helps!
A+, Dom
No comments:
Post a Comment