C# List of Generic Abstract Class [closed]

Presentation: Hello, I’m a free-time game developer. I wondered if I should look for help in the Game Development Stackexchange or even Unity Answers, but It seems more like a C# problem, rather than engine (Unity) stuff.

I did look through many other questions here and on those sites and watched some tutorials, but didn’t get It yet, that’s why I’m here.

Summary: Im making a modular windows system for my game UI, and they should have the current features:

  • Should be called and referenced by a singleton manager UIManager.cs;
  • All windows should have some default methods and some fields;
  • The base class that all windows inherits from, needs to be serializable so the Unity engine can show them on a visual interface, making easy setting the fields. Example of Serializable Class as a visual component.
  • Finally, It also should be easy to get and use a windows from code, since some methods will immediately call them directly from the code.

Problem: I need to hold a reference of the generic abstract script that holds de default fields and methods in a List but It seems I can’t find a way to declare said List.

Code Files:

UIManager.cs (This is a singleton that will manage any and all UI elements) Error code on Visual Studio Community 2019

using System.Collections.Generic;
// Unity namespace.
using UnityEngine;

// Inherits my custom singleton abstract.
public class UIManager : MonoSingleton<UIManager>
{

    // THE PROBLEM! I use Lists here and there, but never tried with generics. 
    public List<MonoWindow<T>> windows;

    public override void Init()
    {
        Debug.Log("Window 0: " + typeof(windows[0].windowType).ToString());
    }
}

MonoWindow.cs (The generic abstract class that is giving me such a headache, hold the default fields and methods for all windows)

using System;
// Unity namespace.
using UnityEngine;

// All the windows inherit this, and I also need to know here which script is inheriting it, so there's the T.
public abstract class MonoWindow<T> : MonoBehaviour where T : MonoWindow<T>
{
    public T windowType; // No value needed, only need to know what type (T) of windowType I'm dealing with.
    public WindowCategory category; // WindowCategory is an enum.
    public bool isFocused;

    private void Awake()
    {
        Init();
    }

    // Optional override.
    public virtual void Init() { }
}

LogWindow.cs (Example of a window script that inherits the MonoWindow).

using System.Collections.Generic;
// Unity namespace.
using UnityEngine;

// It inherits MonoWindow, passing its own type LogWindow as the parameter (Should be the value of T).
public class LogWindow : MonoWindow<LogWindow>
{
    public override void Init()
    {
        // Initialize window stuff.
    }

    // Specific window methods.
}

Considerations: First, I can’t set those fields as properties on a interface since the last is non-serializable. Second, if you guys have a better approach for this, feel free to throw your own opinions on usability, ease-of-use, maintenance, performance, etc. Third, If any more info is required, let me know, I think I covered everything about C# though.

Answer

Note that the way you try to print it wouldn’t work anyway

typeof(windows[0].windowType).ToString())

since typeof doesn’t work with dynamic types but expects a compile time constant type like e.g.

typeof(MonoBehaviour) 
typeof(int)
...

However, You say yourself

No value needed, only need to know what type (T) of windowType I’m dealing with.

You don’t even need your class to be generic at all! (A classical case of an XY problem)

What you are interested in is only the Type of your window so you can simply use object.GetType

public abstract class MonoWindow : MonoBehaviour
{
    // You want the TYPE not a reference!
    // This is a read-only property
    public Type windowType => this.GetType();
    // you could also write it as
    //public Type windowType
    //{
    //    get => this.GetType();
    //}
    // Or also
    //public Type windowType
    //{
    //    get
    //    {
    //        return this.GetType();
    //    }
    //}

    public WindowCategory category;
    public bool isFocused;

    // You should make this virtual as well!
    // If you don't any child might be implementing Awake and hide this one
    // => This Awake would not get called in such a case
    protected virtual void Awake()
    {
        Init();
    }

    // So after the comment on Awake it is questionable if you need this method at all 
    // your inheritors could as well override Awake instead.
    // also why is this public if it is called automatically in Awake anyway?
    public virtual void Init() { }
}

If you even need such a windowType property again is highly questionable since you also could directly use it on the implementation level:

public override void Init()
{
    Debug.Log("Window 0: " + windows[0].GetType().ToString());
}

Leave a Reply

Your email address will not be published. Required fields are marked *