Search Unity

Convert Singleton<T> to T

Discussion in 'Scripting' started by Sp1ceForce, Jan 16, 2022.

  1. Sp1ceForce

    Sp1ceForce

    Joined:
    Aug 13, 2020
    Posts:
    5
    Hello, i am trying to implement a parent Singleton class, but when i try to assign instance to "this" its telling me that it cannot convert type Singleton<T> to T
    Here's the code:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Singleton<T>:MonoBehaviour where T : MonoBehaviour
    4.     {
    5.     public static T s_instance { get; private set; }
    6.    protected virtual void Awake()
    7.     {
    8.         if (!s_instance)
    9.         {
    10.             s_instance = this;
    11.             DontDestroyOnLoad(this);
    12.         }
    13.         else
    14.         {
    15.             Destroy(gameObject);
    16.         }
    17.     }
    18. }
     

    Attached Files:

  2. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,999
    Your generic constraint is wrong. Your only condition is that T has to be any type derived from MonoBehaviour. It doesn't have to be derived from Singleton<T> at the moment. So in theory you could create a class like this

    Code (CSharp):
    1. public class TestBehaviour : MonoBehaviour
    2. {
    3.  
    4. }
    And a singleton like this:

    Code (CSharp):
    1. public class SomeSingleton : Singleton<TestBehaviour>
    2. {
    3.  
    4. }
    Of course the class in the type argument has absolutely nothing to do with the SomeSingleton class.

    Your constraint has to look like this:

    Code (CSharp):
    1. public class Singleton<T> : MonoBehaviour where T : Singleton<T>
    Even though it looks like a recursive definition (which it actually is), it will make it work. That's because whatever class you derive from your Singleton class must use itself in the T argument, no other class would match the constraint.

    Note that this kind of singleton (Awake initialized) is a quite specialized form. Initialization in Awake could cause race conditions if you try to use this singleton in other awake methods. Usually a FindObjectOfType approach is more flexible. In theory one could combine both approaches, but I like to have Awake available for the singleton itself.

    Finally in your implementation you silently destroy any duplicate instance. This is bad for debugging. You decided you want to have a gameobject based singleton. So there must always be just one instance. If there is another one, there's something fundamentally wrong. Instead of deleting the duplicate, throwing an exception or logging an error usually makes more sense since something in the setup is flawed and needs attention.
     
    ahSOLO1, Sp1ceForce and SisusCo like this.
  3. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,330
    One small limitation with the lazy FindObjectOfType approach is that it can result in exceptions if the singleton is first accessed from a background thread, since FindObjectOfType is not a thread safe operation.

    In most cases this isn't an issue, but if you might potentially want to be able to use a singleton for example inside ISerializationCallbackReceiver methods, constructors or worker threads you yourself have started it's something to keep in mind.
     
    Last edited: Jan 16, 2022
    Sp1ceForce likes this.