【问题标题】:Is delayed initialization good or bad? [closed]延迟初始化是好是坏? [关闭]
【发布时间】:2019-12-12 17:32:34
【问题描述】:

我刚刚找到一个同事创建的名为 HmeRevisionTracker 的类。它只包含一个简单对象的 List。 CSimCharge 是该项目中最重要的类之一,它包含一个 HmeRevisionTracker 对象作为公共属性,声明如下:

    public HmeRevisionTracker RevisionTracker { get; private set; }

没有理由不能在 CSimCharge 构造函数中创建对象,因为 HmeRevisionTracker 是完全硬编码的,不会改变它。但它不是在那里创建的。相反,它被初始化为 jull。在使用之前不会创建它:

    void CheckForHeatModelRevision()
    {
        // Find the next revision that needs to be performed
        if (RevisionTracker == null && UseModel)
            RevisionTracker = new HmeRevisionTracker(ActualBase.CoilLoad, ActualBase.IsHeating);

据我所知,这没有问题,但我很好奇。这段代码有什么我不知道的缺点吗?

实现对于这个问题应该无关紧要,但无论如何这里有一些:

public class HmeRevisionRule
{
    public double CheckPointThreshold { get; private set; }
    public bool RevisionNeeded { get; set; }
    public bool IsHeatingRule { get; private set; }
    public bool IsCoolingRule { get { return !IsHeatingRule; } }

    public HmeRevisionRule(double threshold, bool isHeatingRule)
    {
        CheckPointThreshold = threshold;
        RevisionNeeded = true;
        IsHeatingRule = isHeatingRule;
    }
}

public class HmeRevisionTracker
{
    public LinkedList<HmeRevisionRule> CheckPointRules { get; private set; }

    public HmeRevisionTracker(CSimCoilGroup coilLoad, bool isHeating)
    {
        CheckPointRules = new LinkedList<HmeRevisionRule>();

        // Default Heating & Cooling Check Points
        CheckPointRules.AddLast(new HmeRevisionRule(1.0 / 2.0, true));
        CheckPointRules.AddLast(new HmeRevisionRule(3.0 / 4.0, true));
        CheckPointRules.AddLast(new HmeRevisionRule(7.0 / 8.0, true));
        CheckPointRules.AddLast(new HmeRevisionRule(15.0 / 16.0, true));
        CheckPointRules.AddLast(new HmeRevisionRule(63.0 / 64.0, true));

        CheckPointRules.AddLast(new HmeRevisionRule(1.0 / 2.0, false));
        CheckPointRules.AddLast(new HmeRevisionRule(3.0 / 4.0, false));
        CheckPointRules.AddLast(new HmeRevisionRule(7.0 / 8.0, false));
        CheckPointRules.AddLast(new HmeRevisionRule(15.0 / 16.0, false));
        CheckPointRules.AddLast(new HmeRevisionRule(63.0 / 64.0, false));

        Initialize(coilLoad, isHeating);
    }

初始化根据充电状态设置单独的规则。该类的其他方法检索所需的规则或更改规则的设置。

【问题讨论】:

    标签: c# initialization lazy-initialization


    【解决方案1】:

    这称为延迟初始化,是提高性能的常见做法。将其标记为“好”或“坏”是主观的,并且取决于使用它的环境。

    在您的示例中,HmeRevisionTracker 类的初始化可能很昂贵,因此仅应在实际需要时进行。当RevisionTracker 是其他代码可能依赖的null 时,还可能有其他一些含义(即,它可能表明尚未调用其他方法,描述一些内部状态)。

    有一篇关于懒惰初始化话题here的文章,部分说明:

    延迟初始化主要用于提高性能、避免计算浪费和减少程序内存需求。最常见的情况是:

    • 当您有一个创建成本很高的对象时,程序可能不会使用它。
    • 当您有一个创建成本很高的对象,并且您希望将其创建推迟到其他成本很高的操作完成之后。

    如文章中所述,在 .NET 4.0 中引入了一个 Lazy&lt;T&gt; 类,可用于使这一点更加有意并可能减少代码行数。


    最后,关于你的陈述:

    在 CSimCharge 构造函数中无法创建对象是没有原因的

    微软的Member Design Guidelines on Constructor Design 状态:

    ✓ 做最少的工作在构造函数中。

    除了捕获构造函数参数之外,构造函数不应做太多工作。任何其他处理的成本应延迟到需要时。

    (感谢@madreflection 的这一部分!)

    【讨论】:

      【解决方案2】:

      我的个人意见认为,当构造函数完成时,对象应该“准备好使用”:因此应该在构造函数中构建List 对象。今天,执行此操作所需的几纳秒已经无关紧要。但是意外的运行时错误和由此产生的(生产?)应用程序崩溃可能会花费很多钱。在构造函数中构造所有必要的东西,即使它们没有被使用,并在析构函数中将它们拆除。

      如果属性是private 并且可能实际上没有被使用,则将其明确初始化为null。最重要的一点是该值不是不可预测的。(“它不是零,但它没有任何好处。”)

      【讨论】:

      • 您指的是什么“意外的运行时错误和导致的(生产?)应用程序崩溃”
      • 示例问题中的对象如何不“准备好使用”(OP 声明 “据我所知,这没有问题”)?另外,说它只节省“几纳秒”的依据是什么(我们没有看到Initialize(coilLoad, isHeating); 背后的代码,它可能会初始化一些额外的对象、进行数据库调用和/或运行密集的文件操作),当我们不知道程序在做什么时,你怎么能说“纳秒...无关紧要”?不批评这个答案,只是要求更多澄清。
      • 这是基于意见的。许多开发人员认为 ctor 应该是轻量级的并且不要做任何繁重的工作。如果您必须创建一百万个对象但不需要昂贵的初始化怎么办?如果您的开发人员忘记调用 init 函数,那么您很快就会知道,这是一个容易修复的错误。创建一个空列表很好。
      • 关于“几纳秒”:初始化相对简单,所需时间微不足道。感谢大家抽出宝贵时间回复。
      猜你喜欢
      • 1970-01-01
      • 2020-05-10
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-08
      • 2017-11-11
      相关资源
      最近更新 更多