Search Unity

Template class and static member (C#)

Discussion in 'Scripting' started by domderrien, Jan 20, 2014.

  1. domderrien

    domderrien

    Joined:
    Mar 6, 2013
    Posts:
    2
    Hi,

    I tried to code a singleton within a template class and I've been surprised that the singleton is only unique per resolved class, not for all resolved classes! Here is the code to reproduce the issue:

    Code (csharp):
    1. public class TemplateClassWithStaticMember<T> {
    2.     public static string member = "007";
    3.     public static string GetMember() {
    4.         UnityEngine.Debug.Log("GET<" + typeof(T).Name + ">: " + member);
    5.         return member;
    6.     }
    7.     public static void SetMember(string value) {
    8.         UnityEngine.Debug.Log("SET<" + typeof(T).Name + ">: " + member + " => " + value);
    9.         member = value;
    10.     }
    11.  
    12.     public static void SetAndGetStaticMember() {
    13.         TemplateClassWithStaticMember<System.Int16>.SetMember("'Member reset'");
    14.  
    15.         TemplateClassWithStaticMember<System.Int64>.GetMember();
    16.         TemplateClassWithStaticMember<System.Int16>.GetMember();
    17.         TemplateClassWithStaticMember<string>.GetMember();
    18.     }
    19. }
    When the code is run, the following output is produced :
    • SET<Int16>: 007 => 'Member reset'
    • GET<Int64>: 007
    • GET<Int16>: 'Member reset'
    • GET<string>: 007
    I guess it's due to the call to the static setter and getter with a resolved class, which produces a new class on the fly, then isolating a singleton in each of them...

    Questions: Am I right ? What did I miss?

    My current work around is about declaring a companion internal static class which hosts the singleton. Whatever the setter of a resolved template class I call, now any other getter can get the expected value.

    Code (csharp):
    1. internal static class StaticClassWithStaticMember {
    2.     public static string member = "007";
    3.     public static string GetMember(System.Type t) {
    4.         UnityEngine.Debug.Log("GET<" + t.Name + ">: " + member);
    5.         return member;
    6.     }
    7.     public static void SetMember(System.Type t, string value) {
    8.         UnityEngine.Debug.Log("SET<" + t.Name + ">: " + member + " => " + value);
    9.         member = value;
    10.     }
    11. }
    12.  
    13. public class TemplateClassWithStaticMember<T> {
    14.     public static string GetMember() {
    15.         return StaticClassWithStaticMember.GetMember(typeof(T));
    16.     }
    17.     public static void SetMember(string value) {
    18.         StaticClassWithStaticMember.SetMember(typeof(T), value);
    19.     }
    20.  
    21.     public static void SetAndGetStaticMember() {
    22.         TemplateClassWithStaticMember<System.Int16>.SetMember("'Member reset'");
    23.  
    24.         TemplateClassWithStaticMember<System.Int64>.GetMember();
    25.         TemplateClassWithStaticMember<System.Int16>.GetMember();
    26.         TemplateClassWithStaticMember<string>.GetMember();
    27.     }
    28. }
    Note: my current code is much leaner, with simple accessors for the static string member variable.

    Questions: Is there a better way to solve the issue without introducing the intermediate class?
     
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    A static member exist per type.

    Generic class - or template - have the particularity that each implementation of its generic parameter makes a new type.

    For example, List<int> and List<float> are two distinctive types.

    If you want multiple implementation of a generic type to access a single unified field, you don't have much choice but to implement a common non-generic class that would hold your values.

    And I would advice into using properties instead of Get/Set method. Just a bit cleaner and less verbose.
     
  3. domderrien

    domderrien

    Joined:
    Mar 6, 2013
    Posts:
    2
    Thanks for the clarification.
    Coming from the Java world, I did not catch the exact difference between class and type.

    Don't worry, my production code is much cleaner. Here I just wanted to provide code ready to be executed, with the type of the template in the accessors of the static class in the second example.

    Thanks, Dom
     
  4. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Class; the blueprint - code - for the creation of an object at run-time.

    Object; instance in memory, created from a class.

    Type; an object instance that contains the run-time information of an object's class. Every object (even "Type") has an associated Type that can be retrieved with GetType(). When typing "typeof(MyClass)", the compiler replace that syntax with the appropriated instance.

    Code (csharp):
    1.  
    2. if (variable.GetType() == typeof(float))
    3.     Debug.Log("This is a float!");
    4.  
    In C#, you can do properties;

    Code (csharp):
    1.  
    2. private string text = ""; // this is a field
    3.  
    4. public string Text //this is a property
    5. {
    6.     get { return text; }
    7.     set { text = value; }
    8. }
    9.  
    It replaces the need for explicit methods for accessing fields.