c# - 什么反对静态字段?

标签 c# design-patterns static static-members

我在我们的工具中有两个案例,我在使用静态字段进行集成测试时遇到了一些困难。在应用中这些字段是没有问题的。在我的测试中,我基本上使用每种测试方法创建了一个新应用程序。当我在一次测试运行中运行这些时,你可以想象,会有一些问题。首先让我展示两个这样的案例。

案例一

class SomeClass
{
    private static IService service;

    public static void Initialize(IService service)
    {
        SomeClass.service = service;
    }

    public void DoSomthing()
    {
        service.Foo();
    }
}

基本上这个类的对象会被大量创建。为了能够使用 IService 对象,它被存储为一个静态字段。 在我的测试中,这是一个问题,因为 IService 实际上是一个 IServiceProvider 并且在第一次测试中只检索一次服务。在第二个测试中使用第一个测试的服务。 在实际应用中只有一个IServiceIServiceProvider。因此我们在这里没有问题。

案例二

abstract class BaseClass
{
    private static readonly Lazy<SpecificClass> specificClass = new Lazy<SpecificClass>(() => new SpecificClass());

    public static SpecificClass SpecificClass
    {
        get { return specificClass.Value; }
    }
}

class SpecificClass : BaseClass
{

}

这对我的测试来说更加麻烦,因为即使我创建了一个全新的应用程序,当 SpecificClass 在第一次测试中使用时,它在第二次测试中是同一个对象。 在我的测试中,我这里有内存泄漏,因为 SpecificClass 有一个列表,它会记住第一个测试中的对象。随着每次测试,越来越多的对象被添加到列表中。 在实际应用程序中,列表仅在应用程序启动时填充一次。所以这里没有内存泄漏。

我知道,测试通常会显示设计缺陷,但我在这里看不到。我能想到的删除这些静态字段的唯一论据是,否则我的测试不起作用。

那么我现在的问题是,为什么在这些情况下使用静态字段被认为是错误的代码,或者不是?我不想知道这些案例的解决方案。除了“我无法正确测试它”之外,我只需要说明为什么需要更改代码。

最佳答案

这里的设计缺陷是一个组件决定了其依赖项的生命周期,这在实际应用程序中是很糟糕的,并且在编码测试时会让事情变得更难。

您需要的是使用支持依赖注入(inject)的控制反转容器,并让它通过配置注入(inject)依赖的生命周期来决定。

例如,在 Castle Windsor 中它将配置如下:

IWindsorContainer container = new WindsorContainer();
container.Register
(
     Component.For<SomeClass>().LifeStyleTransient(),
     Component.For<IService>().ImplementedBy<SomeService>().LifeStyleSingleton()
);

所以你决定 IService 通过配置是一个单例,但你的代码依赖于 SomeClass 的实例将被注入(inject)一个 实现的实例IService.

Why is it bad for the actual application. I only need a justification why a change in the code is necessary.

  • 没有简单的单元测试:如果不使用实例构造函数和/或属性,就不能使用自动依赖注入(inject)。这会使您的代码更难测试,因为简单的配置无法注入(inject)而不是实际实现。

  • 没有自动依赖注入(inject)。不能将不同的应用程序和服务配置为使用相同或不同的依赖接口(interface)实现,并且您将失去一个大特性:对象生命周期( transient 、单例、每个请求、每个线程)可以通过配置和你的代码不应该意识到这一点。

  • 无单一职责原则。您的类是否负责决定其依赖项的生命周期,或者不是应该定义它的框架?

你在问题​​的评论中对 Jon Skeet 说:

@JonSkeet I know why they are bad for my tests. But that is no accepted argument as long as it works for the real application. That is why I want to find a different argument. –

软件质量与实际应用一样真实。如果开发高质量的软件对您来说不是一个可接受的论点,也许您需要追根溯源,找出为什么应用程序或服务必须是可测试的

关于c# - 什么反对静态字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35645597/

相关文章:

c++ - 在声明或实现中延迟初始化 C++ 单例

swift - 方法中使用的协议(protocol)静态变量

php - 不应静态调用非静态方法 utf_normalizer::nfc()

c# - 可排序的绑定(bind)列表<T> : confusion about RemoveSortCore

c# - 创建一个程序(C#)来捕获我想要的 Html 链接并将结果导出到 Excel 文档

c# - 如何将 WPF 计时器格式化为 HH :MM:SS

c# - 当我在两者之间使用 MessageBox.Show() 时,我的代码如何工作,没有它就不能工作?

java - 如何在 Java 中实现 FSM - 有限状态机

ios - Objective-C 如何正确实现协议(protocol)或其他解决方案

c++ - 我如何在 visual studio 的监 window 口中列出和监视所有全局变量(对于 c++)?