1. We've introduced thread tags, search within a thread and similar thread search. Read more here.
    Dismiss Notice
  2. We've released our first Timeline Experimental Preview, our new tool for creating cutscenes and more! To check it out click here.
    Dismiss Notice
  3. All Unity Pro perpetual license customers: your special offer to subscribe is ready! Click here.
    Dismiss Notice
  4. Unity 5.5 is now released.
    Dismiss Notice
  5. Check out all the fixes for 5.5 in patch releases 1 & 2.
    Dismiss Notice
  6. Unity 5.6 beta is now available for download.
    Dismiss Notice
  7. Get prepared for the Tizen Mobile App Incentive Program! Read more about the upcoming program here.
    Dismiss Notice
  8. Enter the Microsoft Developer Challenge for a chance to win prizes. Read more about it here.
    Dismiss Notice

Template class and static member (C#)

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

  1. domderrien

    domderrien

    Joined:
    Mar 6, 2013
    Messages:
    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
    Messages:
    2,132
    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
    Messages:
    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
    Messages:
    2,132
    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.