Generic Services

  10. Advanced No Comments

Types that contain generic type parameters can also be registered as global services by adding the [Service] attribute to them:

using Sisus.Init;

[Service]
public class Logger<T>
{
    public void Info(string message) => Debug.Log(typeof(T).Name + " - " + message);
}

When this is done, no instance of the global service is created automatically during initialization – even if you do not set LazyInit to true on the [Service] attribute. Instead, an instance will only be created lazily at the moment when the first client that depends on it is being initialized:

using Sisus.Init;
using UnityEngine;

public class Client : MonoBehaviour<Logger<Client>>
{
    // The Logger<Client> object gets created when the first Client component is being loaded
    protected override void Init(Logger<Client> logger) => logger.Info("Hello, World!");
}

If multiple clients depend on the global service, but with different generic type arguments, then a new global service instance is created for each different variation that is requested by a client (e.g. Logger<Client1>, Logger<Client2> etc.).

It is also possible to register the service using a generic interface as its defining type:

using Sisus.Init;

[Service(ILogger<>)]
public class Logger<T> : ILogger<T>
{
    public void Info(string message) => Debug.Log(typeof(T).Name + " - " + message);
}

Then clients can depend on the interface type instead of the concrete type of the service:

using Sisus.Init;
using UnityEngine;

public class Client : MonoBehaviour<ILogger<Client>>
{
    protected override void Init(ILogger<Client> logger) => logger.Info("Hello, World!");
}

If you can’t (or don’t want to) add the [Service] attribute to the generic type directly – for example, because it’s part of a third-party package – then you can define a service initializer with a generic type parameter and add the [Service] attribute to it instead. Init(args) can lazily determine the generic type argument for the service initializer based on the service type that is being requested by a client.

Here is an example of how ZLogger could be registered as your global logging service using a generic service initializer:

using Microsoft.Extensions.Logging;
using Sisus.Init;
using UnityEngine;
using ZLogger.Unity;

[Service(typeof(ILogger<>))]
sealed class ZLoggerInitializer<T> : ServiceInitializer<ILogger<T>>
{
    public override ILogger<T> InitTarget()
    {
        var factory = LoggerFactory.Create(configure =>
        {
            configure.SetMinimumLevel(LogLevel.Trace);
            configure.AddZLoggerUnityDebug();
        });

        return factory.CreateLogger<T>();
    }
}

 

Leave a Reply

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