MonoBehaviour Inheritance, Singletons and Generics

I’m trying to set up an AudioManager that can be reused across projects without having to rewrite the key pieces each time. The problem I’m having is that if I extend this AudioManager (ie, MyProjectAudioManager), other classes are unable to access additional features added in the subclass.

Here are the implementation details:

First, I have a generic Singleton class that I use for Managers like this:

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{ 
    // ... singleton implementation
    // similar to http://wiki.unity3d.com/index.php?title=Singleton#Generic_Based_Singleton_for_MonoBehaviours

    public static T instance;
}

Then I subclass that for my generic audio manager, where T is an enum of the available audio files. (actually I have a subclass, PersistentSingleton, in between, which makes the singleton persist across scenes).

public abstract class AudioManager<T> : Singleton<AudioManager<T>>
{
    public abstract IAudioLoader<T> audioFiles { get; }

    public void PlayAudio(T audioType)
    {
        AudioClip clip = audioFiles.GetAudioClip(audioType);
        // play the clip!
    }
}

I’m trying to use the generic here so that I can use an enum to specify which audio files are available on a given project, ie

public enum MyProjectAudioType
{
    Blip,
    Bloop,
    ...
}

And the same type is supplied to the generic loader class, so that it is in charge of loading the audio file from Resources:

public class MyProjectAudioLoader : IAudioLoader<MyProjectAudioType>
{
    public AudioClip GetAudioClip(MyProjectAudioType type)
    {
        // check for cached version, otherwise load from Resources
    }
}

Finally, I have my specific project implementation of the AudioManager, which ends up being pretty simple, as it just ties together the specific project audio type and allows me to attach the manager to a GameObject to be used in the scene. (The actual implementation has another subclass in between that differentiates between a Music Manager or Sound Effects Manager, but that doesn’t seem related to my problem)

public class MyProjectAudioManager : AudioManager<MyProjectAudioType>
{        
    public MyProjectAudioLoader myAudioFilesLoader;
    public override IAudioLoader<MyProjectAudioType> audioFiles { get { return myAudioFilesLoader; } }

    public void MyCustomFunction() { ... } // any sort of custom functionality
}

Then for each project, its just a matter of defining the available audio clips, and calling MyProjectAudioManager.instance.PlayAudio(MyProjectAudioType.Blip);
The system manages caching clips, pooling audio sources, unloading unused resources under heavy load, etc.

Now, the problem is, if I define a custom function within the specific MyProjectAudioManager, I can’t seem to access it through the singleton instance. (ie, MyProjectAudioManager.instance.MyCustomFunction(); ). Maybe it has to do with the fact that the AudioManager base class is inheriting from the Singleton, and not the project specific audio manager. But I don’t understand why that would affect it like this, and I’m not really sure how to resolve the issue. Any suggestions on whats going on and how to fix it? Alternative solutions that would still allow me to reuse base classes without having to rewrite it on every project?

Finally solved this by changing some of the class defintions:

public abstract class AudioManager<M, T> : Singleton<M> where M : MonoBehaviour { ... }

public class MyProjectAudioManager : AudioManager<MyProjectAudioManager,MyProjectAudioType> { ... }