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