【问题标题】:Setting Static Field in Non-static Constructor | Why does this work? | C#在非静态构造函数中设置静态字段为什么这行得通? | C#
【发布时间】:2021-11-03 10:16:05
【问题描述】:

在这个应用程序中,我们使用带有自定义函数的JUST.net。 JUST.net 中的自定义函数必须是静态方法。我创建了一个定义所有静态函数的类;这些函数通过反射注册到 JUST.net 上下文。我需要在这些静态函数中包含日志记录,以防其中一个映射失败。

为了实现这一点,我们有这样的代码:

public class Transformations
{
  private static ILogger<Transformation> _logger;

  public Transformations(ILogger<Transformations> logger)
  {
     _logger = logger;
  }

  public static string MapAddress(string? streetNumber, string? streetName)
  {
    if(string.IsNullOrEmpty(streetNumber)
    { 
      _logger.LogError("The property was not provided.");
    }
    // etc...
  }
  // etc...
}

当我从测试中调用它时,如果我实例化类并静态引用函数,记录器就会工作。如果我不实例化类并静态引用方法,则记录器不起作用。

即:

  public class AddressUnitTest
  {
    private readonly Transformations _transformations;

    public AddressUnitTest()
    {
      var serilog = new LoggerConfiguration().WriteTo.Console().CreateLogger();
      var loggerFactory = new LoggerFactory().AddSerilog(serilog);
      var logger = loggerFactory.CreateLogger<Transformations>();
      _transformations = new Transformations(logger);
    }

    [Fact]
    public void Address(string? streetNumber, string? streetName)
    {
      var actualValue = Transformations.MapAddress(streetNumber, streetName);
      // etc...
    }
  }

鉴于您不能使用 _transformations.MapAddress() 并且必须静态引用这些方法,即:Transformation.MapAddress(),为什么当我实例化一个看似无关的版本时记录器会工作?

也就是说,为什么设置_transformations = new Transformations(logger); 会赋予Transformations.MapAddress() 对记录器的访问权限?

它似乎有效;我只是不明白为什么。有没有更好的方法来做到这一点?

【问题讨论】:

  • 你自己用这种奇怪的方式写的。 _logger 字段是静态的,您在实例构造函数中分配此静态字段。静态方法当然可以访问静态字段,因此不太清楚混乱的来源。当然这种方法不好 - 只需删除构造函数并使用类似public static SetLogger(ILogger ...) 的方法。

标签: c# logging static-methods


【解决方案1】:

原因是 _logger 字段被初始化为任何东西的唯一时间是在类构造函数中。

最好写一个静态方法来初始化记录器,并使你的整个类成为静态的(这样它的所有成员都必须是静态的),这样就不会出现这种混乱:

public static class Transformations
{
  private static ILogger<Transformation> _logger;

  public static void InitialiseLogger(ILogger<Transformations> logger)
  {
     _logger = logger;
  }

  public static string MapAddress(string? streetNumber, string? streetName)
  {
    if(string.IsNullOrEmpty(streetNumber)
    { 
      _logger.LogError("The property was not provided.");
    }
    // etc...
  }
  // etc...
}

在您的单元测试中,应该有一个启动方法,它只为所有单元测试调用一次Transformations.InitialiseLogger(),因此您不必在每个测试方法中重复它。 (或其他方式 - 我不熟悉 xUnit 是如何做到这一点的。)

【讨论】:

    猜你喜欢
    • 2015-06-28
    • 2013-12-25
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 2014-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多