การแคชคุณสมบัติหรือฟิลด์ที่มีราคาแพงต่อการคำนวณใหม่ในบันทึก C #

ฉันมีบันทึก C# ดังต่อไปนี้ พร้อมคุณสมบัติที่มีราคาแพงในการคำนวณ:

sealed record MyAwesomeRecord(Dictionary<int, int> SomeDictionary)
{
    public int ExpensiveToComputeProperty => SomeDictionary.Sum(e => e.Value);

    //...
}

var original = new MyAwesomeRecord( new() { [0] = 0 });
var modified = original with { SomeDictionary = new() { [1] = 1 } };

แทนที่จะคำนวณค่า ExpensiveToComputeProperty อีกครั้งในทุกการเข้าถึง ฉันต้องการคำนวณเพียงครั้งเดียวหลังจากการก่อสร้าง แต่เห็นได้ชัดว่าด้วยบันทึก C# ตัวสร้างจะไม่ถูกเรียกใช้อีกครั้งหลังจากแก้ไขด้วย with ฉันลองวิธีต่อไปนี้เพื่อแก้ไขปัญหานี้:

  • ใช้ class ปกติแทน แต่ด้วยวิธีนี้ ฉันจะไม่สามารถใช้ไวยากรณ์ with ซึ่งฉันต้องการใช้ต่อไปได้อีกต่อไป
  • เก็บ ExpensiveToComputeProperty ไว้ในคุณสมบัติหรือฟิลด์ปกติ สิ่งนี้ใช้ไม่ได้เนื่องจากมีการกำหนดค่าเริ่มต้นเพียงครั้งเดียว แต่ไม่ใช่หลังจากเปลี่ยน SomeDictionary ด้วย with
  • AFAIK มีแผนที่จะแนะนำไวยากรณ์ที่ดีที่จะให้ฉันอัปเดตคุณสมบัตินี้ใน C# 10 น่าเสียดายที่ C# 10 ยังไม่อยู่ที่นี่

มีวิธีใช้บันทึกที่หลีกเลี่ยงการทำการคำนวณราคาแพงซ้ำหรือไม่?


person Simon    schedule 30.01.2021    source แหล่งที่มา
comment
แทนที่จะใช้ตัวตั้งค่าเริ่มต้นสำหรับคุณสมบัติ คุณสามารถใช้ตัวตั้งค่าแบบกำหนดเองได้ ในตัวตั้งค่านี้ คุณสามารถทำซ้ำการคำนวณที่มีราคาแพงได้   -  person Xaver    schedule 30.01.2021
comment
@Xaver ความคิดเยี่ยมมาก! หากคุณโพสต์สิ่งนี้เป็นคำตอบฉันจะยอมรับมัน   -  person Simon    schedule 30.01.2021
comment
ตกลง ฉันจะทำอย่างนั้น (และเพิ่มโค้ดอีกเล็กน้อย)   -  person Xaver    schedule 30.01.2021
comment
ไม่จำเป็น (สำหรับฉัน) แต่อาจดีสำหรับคนอื่นๆ ไอเดียได้ผล!   -  person Simon    schedule 30.01.2021


คำตอบ (1)


แทนที่จะใช้ตัวตั้งค่าเริ่มต้นสำหรับคุณสมบัติ คุณสามารถใช้ตัวตั้งค่าแบบกำหนดเองได้ ในตัวตั้งค่านี้ คุณสามารถคำนวณราคาแพงได้

นี่คือตัวอย่างที่สมบูรณ์ (ทดสอบแล้วและใช้งานได้):

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    sealed record MyAwesomeRecord
    {
        public MyAwesomeRecord(Dictionary<int, int> SomeDictionary)
        {
            this.SomeDictionary = SomeDictionary;
        }

        public int ExpensiveToComputeProperty { get; private set; }

        private Dictionary<int, int>? _SomeDictionary;
        public Dictionary<int, int> SomeDictionary
        {
            get => _SomeDictionary!;
            set
            {
                _SomeDictionary = value;
                ExpensiveToComputeProperty = SomeDictionary.Sum(e => e.Value);
            }
        }

        //...
    }

    class Program
    {
        static void Main()
        {
            var original = new MyAwesomeRecord(new() { [0] = 0 });

            Console.WriteLine($"ExpensiveToComputeProperty = {original.ExpensiveToComputeProperty}");

            var modified = original with { SomeDictionary = new() { [1] = 1 } };

            Console.WriteLine($"ExpensiveToComputeProperty = {modified.ExpensiveToComputeProperty}");
        }
    }
}
person Xaver    schedule 30.01.2021