【发布时间】:2021-07-07 07:48:52
【问题描述】:
我正在尝试设置本机记录器以调用 C# 函数。由于在本机端登录是使用单例 (log4cpp) 设置的,因此我需要确保尽早设置侦听器(在任何其他本机调用之前)。所以我决定遵循以下建议:
因此我编写了以下静态类(充当我的单身人士):
internal static class MyNativeService
{
private const string NativeLibraryName = "my.so.0";
private static Delegate _logDelegate; // to prevent garbage collection of C# delegate
static void LogMessage(int logLevel, string loggerName, string message)
{
Console.WriteLine($"{logLevel} - {loggerName} - {message}");
}
static MyNativeService()
{
_logDelegate = new LogDelegate(LogMessage);
IntPtr ptr = Marshal.GetFunctionPointerForDelegate(_logDelegate);
// my_listener_configure should be called before any other native calls (only once)
my_listener_configure(ptr);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal delegate void LogDelegate(int logLevel,
[MarshalAs(UnmanagedType.LPUTF8Str)] string loggerName,
[MarshalAs(UnmanagedType.LPUTF8Str)] string logMessage);
[DllImport(NativeLibraryName, CallingConvention = CallingConvention.Cdecl)]
private static extern void my_listener_configure(IntPtr aCallback);
}
这按预期工作,但这并不是我想要的。我更愿意将消息转发到实际的ILogger 框架(Microsoft.Extensions.Logging)。那么我应该如何重构上面的代码,让我的LogMessage变成:
using Microsoft.Extensions.Logging;
internal class MyNativeLoggerListener
{
private readonly ILogger<MyNativeLoggerListener> _logger; // created somehow at startup
private void LogMessage(int logLevel, string loggerName, string message)
{
_logger.Log((LogLevel)logLevel, 0, $"{loggerName} - {message}", null, null);
}
}
由于我不能混合依赖注入和静态构造函数,我如何以及何时在我的 C# 应用程序中创建我的单例,以设置将本机消息转发到正确配置的记录器(在应用程序中定义)?
另一个天真的解决方案是在Startup 类中创建一个记录器,这样:
namespace Acme
{
public class Startup
{
private readonly ILogger<Startup> _logger;
private readonly Delegate _logDelegate; // to prevent garbage collection of C# delegate
public void LogMessage(int logLevel, string loggerName, string message)
{
_logger.Log((LogLevel)logLevel, 0, message, null, null);
}
public Startup(IConfiguration configuration, ILogger<Startup> logger)
{
Configuration = configuration;
_logger = logger;
_logDelegate = MyNativeService.my_listener_configure(LogMessage);
}
当然,这不会起作用,因为 ILogger 机制尚未设置。上面抛出一个:
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger`1[Acme.Startup]' while attempting to activate 'Acme.Startup'.
作为参考,这是我遵循的模式:
【问题讨论】:
-
MyNativeService 必须是静态类吗?
-
静态构造函数不需要静态类。您可以将静态构造函数添加到非静态类。
标签: c# logging dependency-injection