1

I'm trying to create a class hierarchy such that I can have:

SpecificScreenController < ScreenController < Singleton

So far I have these set up as:

public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T _instance;
    public static T Instance{ get{... return _instance;} }
}

public abstract class ScreenController<T> : Singleton<T> where T : MonoBehaviour
{
    public GAME_SCREEN GameScreen;
    //many more ScreenController common properties/fields/methods
}

public class SpecificScreenController : ScreenController<SpecificScreenController> 
{
    //subclass specific properties, overriden ScreenController methods etc.
}

This way I can use SpecificScreenController.Instance.GameScreen; This works, so far, so good.

What I want to now do with this is, for instance:

List<ScreenController> screenControllers = new List<ScreenController>();
screenControllers.Add(SpecificScreenController.Instance);
ScreenController s = screenControllers.Find(i => i.GameScreen == GAME_SCREEN.THING);

But, of course ... this won't compile because ScreenController now requires a Generic Type etc. What idiom can/should I use to preserve the Singleton behavior and ScreenController sub/superclasses ?

Ben Roberts
  • 199
  • 1
  • 8
  • 2
    [Jon Skeet's blog post on C# Singletons](http://csharpindepth.com/Articles/General/Singleton.aspx). More than you ever wanted to know about creating Singletons in C#. – Robert Harvey Feb 17 '16 at 00:48
  • FWIW, it seems to me that if you want `List`instead of `List>`, then you shouldn't be inheriting from `MonoBehaviour`. – Robert Harvey Feb 17 '16 at 00:49
  • @RobertHarvey interesting read thanks ... the pattern I'm using is as it is for use in the Unity game engine where some properties of MonoBehaviour are getting used to deal with lifecycle events of the singletons. For now I'm stuck inheriting from it but (I assume) this is a generic(heh) question related to nesting generic classes. – Ben Roberts Feb 17 '16 at 00:53
  • You absolutely cannot, realistically, use singletons in Unity. It goes completely against the grain - it never works. This is a very basic fact about Unity. – Fattie Feb 17 '16 at 19:00
  • http://stackoverflow.com/a/35891919/294884 – Fattie Jul 14 '16 at 17:37

2 Answers2

1

The problem here is one of covariance. You're assuming that if SpecificScreenController inherits from MonoBehaviour then ScreenController<SpecificScreenController> also inherits from ScreenController<MonoBehaviour>. It doesn't. You can't do this cast.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • Hi thanks for confirming the issue, really just looking for ways to work around / more elegantly set this up now! – Ben Roberts Feb 17 '16 at 01:49
  • @BenRoberts - No worries. What are you trying to achieve by casting to `ScreenController` anyway? – Enigmativity Feb 17 '16 at 01:50
  • specifically I want to have a List of `ScreenController` subclasses I can iterate over in order to work out which one should be current, which to hide/show etc. – Ben Roberts Feb 17 '16 at 01:54
  • Then you should make all of the classes implement an `IScreenController` interface. Then you can make a `List>` easily. – Enigmativity Feb 17 '16 at 03:17
  • I think the issue with this route is that ScreenController has a bunch of fields which the subclasses use ... where would those go? – Ben Roberts Feb 17 '16 at 04:05
  • @Aurigan - Could you update your question to show the code? It's so much easier when there is a concrete compilable example. – Enigmativity Feb 17 '16 at 04:42
  • I'd have to add a few hundred lines to show everything in these classes and this is in a Unity (a game engine) project so would only compile there. For the sake of discussion I've added a field to ScreenController in the question code though. Hope that helps. – Ben Roberts Feb 17 '16 at 05:35
  • You simply can't have singletons in Unity. It's ***utterly meaningless***. Quite simply, state what GameObject the "singleton" is attached to when the singleton instance instantiates itself. MonoBehavior exist only as components of a physically real GameObject. (This is ECS.) It is ***totally meaningless***. – Fattie Feb 17 '16 at 19:40
  • hi @Aurigan old bean -- did Enig's answer answer your specific question here? If so you should tick an answer please to help keep the board tidy. Cheers! – Fattie Mar 01 '16 at 15:41
  • @Joe Blow not really, it clearly states why some of the code I wrote won't work but doesn't present any solution to the question which is what to do about it. In practice I ended up just accepting that these goals were mutually exclusive and copy-pasted the singleton code into classes that needed it. I'll see if I can add that as an answer, – Ben Roberts Mar 02 '16 at 16:28
-1

As there seem to be no really clean solutions to this issue I ended up removing Singleton from my class hierarchy and copy-pasted non-generic versions of the singleton property get/instantiate code into each of the classes that I wanted to be singletons.

public abstract class ScreenController : MonoBehaviour
{
}

public class SpecificScreenController : ScreenController
{
    private static SpecificScreenController _instance;
    public static SpecificScreenController Instance{ get{... return _instance;} 
}
Ben Roberts
  • 199
  • 1
  • 8
  • I can assure the clean solution is: it is nothing more than a GameObject (and some component on it) .. which you want to access everywhere. Just do that with syntactic candy, such as http://stackoverflow.com/a/35524924/294884 FindObjectOfType. That is utterly clean, and 10000% ECS. GameObjects *are singletons* in ECS, every "thing" in a scene *is a singleton* totally inherently. The "search for singletons" in Unity is a "forest for the trees" confusion. To handle "central services" (say, "sound effects") is the *very raison d'etre* of ECS, what they do. There's no "search for a solution." – Fattie Mar 22 '16 at 20:56
  • using FindObjectOfType is a terrible 'solution' ... This is what the Unity docs say about it: "Please note that this function is very slow. It is not recommended to use this function every frame. In most cases you can use the singleton pattern instead." http://docs.unity3d.com/ScriptReference/Object.FindObjectOfType.html – Ben Roberts Mar 24 '16 at 02:11
  • what are you referring to? obviously you use `FindObjectOfType` **once** in `Awake`. "It is not recommended to use this function every frame" why would you use it every frame? – Fattie Mar 24 '16 at 02:45
  • IMHO your 'preloader' scene concept is more overhead and less usable than just using singletons. It's certainly possible to do and seems to fit with your personal beliefs about singletons in an ECS framework but I just don't share those beliefs. – Ben Roberts Mar 25 '16 at 15:06
  • There can be no such thing as singletons in the ECS concept of Unity, it's not possible. There is simply no way to meaningfully say that a GameObject is a "singleton", it is a meaningless concept. Imagine if you said you were going to have, oh, a "singleton scene". It doesn't even mean anything. You would essentially be saying "well I'm going to have a project, and we're going to ensure it has only the one scene". Similarly applying the term "singleton" to a GameObject just doesn't make sense. Technically it is absolutely impossible (apart from that it would be "whacky") to have only one.. – Fattie Mar 25 '16 at 15:13
  • ...only the one GameObject in a scene. Say, for some reason!, there was a facility in Unity where you could throw a switch and it would only allow one game object (!) in the whole app. Again this would be whacky, it's just a gedanken exercise. In that case, one could make a "singleton" game object, I guess. (Still, any component at all could be on or off it, in many cases multiples of the same.) Given that Unity (of course) does not have said theoretical switch, it's just absolutely impossible to talk of a "singleton" in an ECS system! – Fattie Mar 25 '16 at 15:15
  • When folks started to throw around the idea of having a "singleton-like" GameObject in unity a few yrs ago, of course many scripts appeared which did things like check that there are no other such objects (when? at scene launch? game launch? every frame? every callback that creates or destroys anything? it can't be done of course). Sure, **by all means** it's helpful that in eg. packages, you have those scripts where it nattily "creates an object" for itself, as a matter of convenience (for a sound effects manager or whatever).That's a fine convenience, – Fattie Mar 25 '16 at 15:19
  • , but it's led to thinking where you can "have singletons" ('real ones") in unity. The singleton concept cannot apply to component-GameObject systems. Each GameObject is a "global", it is indeed a "singleton". Anyways cheers – Fattie Mar 25 '16 at 15:21
  • You're wasting your time brother, not only do singletons work in Unity, they have meaning for everyone using them, are useful for a certain class of problems and are even recommended by Unity themselves. – Ben Roberts Mar 26 '16 at 15:59
  • Well, it's just a discussion - and I type fast :) I appreciate your thoughts and challenges. Thanks again. Never a waste of time for me discussing engineering matters. (Anything Unity says is a laughable joke, so we can dismiss that.) As a practical matter, if you're using one of the schemes of "automatically making a GameObject to attach the MonoBehaviour to". Surely you should use one of the schemes of trying to ensure that there can be only one. (This is technically impossible, but you can see many examples around.) In your solution here (ie this answer) it can be duplicated. Cheers – Fattie Mar 26 '16 at 16:03