如果一个类有一个公共入口点,它将所需的一切都作为参数,它应该是静态的吗?

时间:2010-11-03 18:03:00

标签: c# .net static

我刚刚编写了一个类,并意识到它的所有公共功能都封装在一个方法中。它没有属性,没有共享资源,并且不需要构造函数重载并处理它使用的任何内容。它看起来像这样:

public class ReportGenerator
{
    public string GenerateReport(List<SomeClass> stuffToReportOn)
    {
        string fileName = String.Empty;
        using(var reportDs = CreateDataSet(stuffToReportOn))
        {
            //do the stuff with the third party tool that 
            //creates the report.
            //Construct the filename.
            //Save the report.
        }
        return fileName;
    }

    private TypedDataSetRequiredByThirdPartyLib CreateDataSet(List<SomeClass> reportItems)
    {
        //create the dataset, calling two other private methods
        //to build the tables/rows
    }
}

在我完成重构之后,我意识到这个类可能完全是静态的。我的问题是,应该吗?是否应将在一个公共方法中封装其所有功能的类设为静态?

4 个答案:

答案 0 :(得分:5)

没有。什么是预期的好处?

更重要的是潜在的错误。如果在你的类中声明一个静态变量,它只会被初始化一次,它的值将持续存在,并且每个调用的行为可能会有所不同。容易过度查看,这可能很难调试。

答案 1 :(得分:3)

不,它会为这个类 - 或使用这个类的类 - 编写单元测试 - 不可能。

使用像FakeItEasy这样的工具,您甚至不需要该类来实现一个接口就可以模拟它(这意味着您可以快速开始模拟一个未编写的旧代码库)记住TDD,但它无法绕过静态调用。

<强>更新
假设您需要对调用GenerateWidgetReports的方法ReportGenerator.GenerateReport进行单元测试。您需要确保stuffToReportOn仅包含Widget1&amp; Widget2。你如何编码测试?

你最终要做的是让GenerateWidgetReports使用名为GetStuffToReportOn的方法,你可以测试一下,没问题。 GenerateWidgetReports然后变成调用GetStuffToReportOn的粘合剂并将其结果传递给ReportGenerator.GenerateReport

但是,您仍然无法对GenerateWidgetReports进行测试,因为如果没有实际生成报告,则无法调用它。

理想情况下,GenerateWidgetReports的类会获取一个IReportGenerator对象,您可以模拟GenerateReport方法并在其中测试Widget1&amp; Widget2

如果GenerateReport是静态的,则无法使用任何模拟工具执行此操作。

更新2
我更正了,TypeMock可以拦截并重定向调用静态方法。 See this answer

答案 2 :(得分:1)

除了单元测试的困难之外,你应该问问自己:

  1. 我是否对参数进行了更改?如果是这样,多久一次?
  2. 对象是否需要具有状态?
  3. 我需要在整个过程后保留对象吗?
  4. 如果你确定让它成为一个静态类适合你,你也可以决定更进一步做一个扩展方法:

    public static class ReportExtension
    {
        public static string GenerateReport(this List<SomeClass> stuffToReportOn)
        {
            string fileName = String.Empty;
            using(var reportDs = CreateDataSet(stuffToReportOn))
            {
                //do the stuff with the third party tool that 
                //creates the report.
                //Construct the filename.
                //Save the report.
            }
            return fileName;
        }
    
        private static TypedDataSetRequiredByThirdPartyLib CreateDataSet(List<SomeClass> reportItems)
        {
            //create the dataset, calling two other private methods
            //to build the tables/rows
        }
    }
    

    非常确定我的格式是正确的扩展方法。

    编辑:

    您仍然遇到单元测试问题,因为代码依赖于此静态方法。最终,您必须自己决定利弊并做出决定。我可能是错的,但是如果您要将依赖代码作为实例类进行单元测试,那么您可以确信它应该可以作为静态或扩展方法使用。

答案 3 :(得分:0)

是的,这样可以更轻松地使用你的课程。