joshcamas / unity-domain-reload-helper

A couple of attributes that help disabling Domain Reloading in Unity easier
MIT License
185 stars 11 forks source link

Is there a solution for generic classes #2

Open Noxalus opened 3 years ago

Noxalus commented 3 years ago

Hello!

Thank you for this project, it's much more handy that the one proposed by Unity!

I would like to use it to refresh my Singleton class, but it's a generic class and it seems it doesn't work for them.

Here it is:

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    [ClearOnReload(assignNewTypeInstance: true)]
    private static object _lock = new object();
    [ClearOnReload(valueToAssign: null)]
    private static T _instance = null;
    [ClearOnReload(valueToAssign: false)]
    private static bool _hasBeenDestroyed = false;
    [ClearOnReload(valueToAssign: false)]
    private static bool _isQuitting = false;

    /// <summary>
    /// Access singleton instance through this propriety.
    /// </summary>
    public static T Instance
    {
        get
        {
            lock (_lock)
            {
                if (_instance == null && !_hasBeenDestroyed && !_isQuitting)
                {
                    // Search for existing instance.
                    _instance = (T)FindObjectOfType(typeof(T));

                    // Create new instance if one doesn't already exist.
                    if (_instance == null)
                    {
                        // Need to create a new GameObject to attach the singleton to.
                        var singletonObject = new GameObject();
                        _instance = singletonObject.AddComponent<T>();
                        singletonObject.name = typeof(T).ToString() + " (Singleton)";
                    }
                }

                return _instance;
            }
        }
    }
}

I put some debug points in the DomainReloadHandler class and saw that it enters in the catch when calling the field.SetValue method for fields.

Adding a trace for the exception message, I got this:

Late bound operations cannot be performed on fields with types for which Type.ContainsGenericParameters is true.
UnityEngine.Debug:LogError (object)
DomainReloadHandler:OnRuntimeLoad () (at Assets/Plugins/DomainReloadHelper/Editor/DomainReloadHandler.cs:39)

Do you know if there is a solution for this case?

Noxalus commented 3 years ago

I tried to use the ExecuteOnReloadAttribute attribute instead, but same thing, it's working well on simple MonoBehaviour, but the method is not called for generic classes 😢

joshcamas commented 3 years ago

Sorry I didn't see this! I believe I do have a version that adds support to generics, I will push that version soon. :)

toxikman commented 3 years ago

I tried this too with a generic (latest code) and the static values marked with [ClearOnReload] only get cleared once, not once for every generic type that was instantiated. Any update on a fix?

toxikman commented 3 years ago

@Noxalus I created a work-around for singletons, you can call this instead to manage whether a singleton for a certain type has been destroyed:

using TypeTable = System.Collections.Generic.Dictionary<System.Type, bool>;

// ---- Here is where you define your Singleton<T> generic class -----

static class SingletonHelper
{
    [ClearOnReload] private static TypeTable destroyed = null;

    public static bool IsDestroyed(System.Type t)
    {
        return destroyed != null && destroyed.ContainsKey(t);
    }

    public static void MarkDestroyed(System.Type t)
    {
        if (destroyed == null)
            destroyed = new TypeTable();
        destroyed[t] = true;
    }
}
Watcher3056 commented 1 year ago

+1 Very need fix for this. Especially when working with singletons, because this solution is mainly needed for singletons.

stalomeow commented 11 months ago

@Watcher3056 I created a similar project that works for generics. https://github.com/stalomeow/QuickPlayMode