samedi 1 octobre 2022

How can I solve this dependency injection problem?

I have a game written using Silk.NET, the framework has an equivalent of OpenTK's GameWindow with Update and Render methods, etc.

I do log messages using ILogger and I've written an ILogger that redirects message to imgui which is an immediate mode GUI library.

This is the constructor of my game class:

public Game(ILogger<IGame> logger, ILoggerFactory loggerFactory)
{
    Logger = logger;

    ImGuiLogger.Action = s => LoggerQueue.Add(s); // s is a string

    loggerFactory.AddProvider(new ImGuiLoggerProvider());
}

As you can see, I assign an action to a static property in the logger class.

This is what allows me to read the logged messages in my update loop and display them.

So basically, there's a direct dependency and furthermore, I'm assigning a static property which is far from ideal.

This just works as I only have one GUI controller but still, it's not really clean.

This is the logger in question for reference:

using Microsoft.Extensions.Logging;

namespace TestDI.Silk.Logging;

internal sealed class ImGuiLogger : ILogger
{
    public ImGuiLogger(string categoryName, IExternalScopeProvider? scopeProvider)
    {
        CategoryName = categoryName;

        ScopeProvider = scopeProvider;
    }

    private string CategoryName { get; }

    private IExternalScopeProvider? ScopeProvider { get; }

    public static Action<string>? Action { get; set; }

    #region ILogger Members

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
    {
        if (Action is null)
        {
            return;
        }

        var message = formatter(state, exception);

        message = $"{DateTime.Now:HH:mm:ss.fff} [{logLevel.ToString()[..4]}] {CategoryName} {message}";

        Action.Invoke(message);
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return logLevel != LogLevel.None;
    }

    public IDisposable BeginScope<TState>(TState state)
    {
        return ScopeProvider?.Push(state) ?? NullScope.Instance;
    }

    #endregion

    #region Nested type: NullScope

    private sealed class NullScope : IDisposable
    {
        private NullScope()
        {
        }

        public static NullScope Instance { get; } = new();

        #region IDisposable Members

        public void Dispose()
        {
        }

        #endregion
    }

    #endregion
}

Question:

How can I get this logger, to query for an action to execute when it logs a message?

I guess you get the point, i.e. remove that strong reference to a static property.

Aucun commentaire:

Enregistrer un commentaire