C# 如何在仍然允许配置/设置的情况下重构有状态单例?

C# 如何在仍然允许配置/设置的情况下重构有状态单例?,c#,configuration,singleton,elastic-apm,C#,Configuration,Singleton,Elastic Apm,我希望对标准的单例设计模式进行更改,该模式遵循所述的System.Lazy设计。在GitHub中可以看到的Elastic APM代理中,更改为Agent。以下是为简洁起见分解的代码: public static class Agent { private static readonly Lazy<Foo> Lazy = new Lazy<Foo>(() => new Foo(_bar)); private static Bar _bar;

我希望对标准的单例设计模式进行更改,该模式遵循所述的
System.Lazy
设计。在GitHub中可以看到的Elastic APM代理中,更改为
Agent
。以下是为简洁起见分解的代码:

public static class Agent
{
    private static readonly Lazy<Foo> Lazy = new Lazy<Foo>(() => new Foo(_bar));
    private static Bar _bar;
    
    public static Foo Instance => Lazy.Value;
    public static bool IsInstanceCreated => Lazy.IsValueCreated;
    
    public static void Setup(Bar bar) => _bar = bar;
}
在没有注释的情况下,上述代码的未知情读者不能期望
之前
之后
的值不同,只能在查看单个方法的实现后进行解释,这些方法读取和修改隐藏在
配置
单例中的全局状态


主张使用DI来解决这个问题。然而,有没有一种更简单的方法来解决这种情况,即DI不可能实现或需要太多的重构?

作为一种选择,您可以使用类似的方法

公共静态类代理
{
私有静态惰性(u Lazy);;
publicstaticfoo实例=>\u lazy?.Value??抛出新的invalidoOperationException(“请,设置实例”);
公共静态bool IsInstanceCreated=>\u lazy?.IsValueCreated??false;
公共静态无效设置(条形)
{
_懒惰=新懒惰(()=>newfoo(bar));
}
}

在特定情况下,您可以在访问
实例之前检查
IsInstanceCreated
属性。或者初始化setup method中的lazy值这是一个很好的解决方案。这无疑是一个突破性的变化,因为这意味着在
Agent.Setup
之前调用
Agent.Instance
的API用户(知道它将使用
Foo
的默认配置,即传递到其构造函数中的
null
)将突然看到异常。但在继续使用此解决方案之前,我会看看弹性APM代理作者的想法。您可以返回
null
值而不是异常,这取决于您的需要和要求,通常:)检查
IsInstanceCreated
将有助于防止一些错误和副作用,但这仍然是一个突破性的变化,因为他们的代码可能不会检查null,因为这在以前是不期望的。另一方面,他们将得到一个
Foo
实例,该实例未正确初始化,可能稍后会出现异常。我同意,现在最好让消费者知道什么是错误,而不是在
Foo
instance之后得到一个不清楚的异常。当系统被错误地使用时,可以尽早抛出异常(如
InvalidOperationException
)。立即实施。:)
var before = new MyClass().CalculateResult(3, 2);// depends on Configuration.Instance
RefreshConfiguration(); // modifies values in Configuration.Instance
var after = new MyClass().CalculateResult(3, 2); // depends on Configuration.Instance