Operate Just-In-Time

 

Assume we wrote the following definition for a SalesInvoiceLine class:

  public class SalesInvoiceLine
  {
     public string Product { get; }
     public decimal UnitPrice { get; set; }
     public int Quantity { get; set; }
     public decimal Subtotal { get; }

     public SalesInvoiceLine(string product, decimal unitPrice, int quantity)
     {
        Product = product;
        UnitPrice = unitPrice;
        Quantity = quantity;
        Subtotal = UnitPrice * Quantity;
     }
  }

The following unit test verifies the correctness of the Subtotal property:

  [Fact]
  public void Construct_SalesInvoiceLine_Check_Subtotal()
  {
     var line = new SalesInvoiceLine("Apple", 0.35m, 3);
     line.Subtotal.Should().Be(1.05m); // PASSES
  }

The test passes. All is good. Or is it?

Can you see a problem with the definition of SalesInvoiceLine?

 

Let’s add another unit test:

  [Fact]
  public void Update_Quantity_SalesInvoiceLine_Check_Subtotal()
  {
     var line = new SalesInvoiceLine("Apple", 0.35m, 3);
     line.Subtotal.Should().Be(1.05m);

     line.Quantity = 7;
     line.Subtotal.Should().Be(2.45m); // FAILS! 
  }

We construct an instance of SalesInvoiceLine the same as before. Now though, we are increasing the Quantity to 7. 

The unit test fails. Why? 

 

The unit test fails with this message: “Expected line.Subtotal to be 2.45m, but found 1.05m.”

It fails because we calculate the Subtotal property in the constructor.

 

Once again, here is the listing of SalesInvoiceLine with the problematic code bolded:

  public class SalesInvoiceLine
  {
     public string Product { get; }
     public decimal UnitPrice { get; set; }
     public int Quantity { get; set; }
     public decimal Subtotal { get; }

     public SalesInvoiceLine(string product, decimal unitPrice, int quantity)
     {
        Product = product;
        UnitPrice = unitPrice;
        Quantity = quantity;
        Subtotal = UnitPrice * Quantity;
     }
  }

Properties Quantity and UnitPrice have setters; that means we can change them. SalesInvoiceLine instances are mutable—their internal state can vary.

As the code stands, when the UnitPrice or Quantity changes after object construction, it will not affect the Subtotal. We have fixed the Subtotal at construction time!

So how do we overcome this issue?

 

We want to calculate the Subtotal as late as possible—ideally, when we are calling it. In that way, we capture the latest values for the component factors, UnitPrice and Quantity.

The solution? Turn Subtotal into a calculated read-only property:

  public class SalesInvoiceLine
  {
     public string Product { get; }
     public decimal UnitPrice { get; set; }
     public int Quantity { get; set; }
     public decimal Subtotal => UnitPrice * Quantity;

     public SalesInvoiceLine(string product, decimal unitPrice, int quantity)
     {
        Product = product;
        UnitPrice = unitPrice;
        Quantity = quantity;
     }
  }

Since we no longer needed the calculation of Subtotal in the constructor, we have dropped that too. The compiler complained about setting a read-only property; we had to remove it.

 

This technique works well with calculated values, formatting strings and other simple procedures. It doesn’t work well in all situations. When operations are resource-intensive or take a long time, you may find that frequent calls cause performance problems. In that case, you may want to consider other solutions.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply