Menyimpan properti atau bidang yang mahal untuk dihitung ulang dalam data C#

Saya memiliki catatan C# seperti berikut, dengan properti yang mahal untuk dihitung:

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 } };

Daripada menghitung ulang nilai ExpensiveToComputeProperty pada setiap akses, saya ingin menghitungnya hanya sekali, setelah konstruksi. Namun ternyata dengan catatan C#, konstruktor tidak dipanggil lagi setelah modifikasi dengan with. Saya mencoba cara berikut untuk memperbaikinya:

  • Gunakan class biasa sebagai gantinya, tapi dengan begitu saya tidak bisa lagi menggunakan sintaks with, yang ingin terus saya gunakan.
  • Simpan ExpensiveToComputeProperty di properti atau bidang biasa. Ini tidak berhasil, karena diinisialisasi satu kali, tetapi tidak setelah mengubah SomeDictionary dengan with.
  • AFAIK, ada rencana untuk memperkenalkan sintaks yang bagus yang memungkinkan saya terus memperbarui properti ini di C# 10. Sayangnya, C# 10 belum ada.

Apakah ada cara untuk menggunakan catatan yang menghindari pengulangan perhitungan yang mahal?


person Simon    schedule 30.01.2021    source sumber
comment
Daripada menggunakan penyetel default untuk properti, Anda dapat menggunakan penyetel khusus. Di setter ini, Anda dapat mengulang perhitungan yang mahal.   -  person Xaver    schedule 30.01.2021
comment
@Xaver Ide bagus! Jika Anda memposting ini sebagai jawaban, saya akan menerimanya.   -  person Simon    schedule 30.01.2021
comment
Oke, saya akan melakukannya (dan juga menambahkan sedikit kode.)   -  person Xaver    schedule 30.01.2021
comment
Tidak perlu (bagi saya), tapi mungkin bagus untuk orang lain. Idenya berhasil!   -  person Simon    schedule 30.01.2021


Jawaban (1)


Daripada menggunakan penyetel default untuk properti, Anda dapat menggunakan penyetel khusus. Di setter ini, Anda dapat melakukan perhitungan yang mahal.

Berikut adalah contoh lengkap (diuji dan berfungsi):

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