-3

This is a follow up question to my previous one, Make a deep copy of an object inside a ConcurrentDictionary in C#. I want to clone my Patient object so that the object PatientCovariates is the same for the copy.

But when I do that, I also want to regenerate the Random Crn to the same object that was created when the Patient struct was constructed by using _seed.

At the same time, I would like to keep Crn readonly and _seed private and readonly. Is this possible?

using System.Collections.Concurrent;
using System.Text.Json;
namespace ExampleCode;
internal class Program
{
    private static void Main(string[] args)
    {
        Exampel obj = new();
        obj.DoStuff();
    }
}

internal class Exampel()
{
    /// <summary>
    /// For the baseline patients (patient ID, patient object), same for all arms and only generated once
    /// </summary>
    private ConcurrentDictionary<int,
                                 Patient> _baselinePatients = new();

    /// <summary>
    /// Patients in the current arm (patient ID, patient object)
    /// </summary> 
    private ConcurrentDictionary<int,
                                 Patient> _patientsCurrentArm = new();

    public void DoStuff()
    {
        const int EXAMPLE_CYCLE = 0;
        // Set the number of arms and treatments
        int _nArms = 2;
        int _nPatients = 5;

        // Add patients at baseline to _baselinePatients
        for (int i = 0; i < _nPatients; i++) {
            Patient patient = new Patient(1);
            patient.PatientCovariates.Add(0, new());
            _baselinePatients.TryAdd(i, patient);
        }

        // Try to copy the patients created in the baseline ConcurrentDictionary
        for (int i = 0; i < _nArms; i++) {
            for (int j = 0; j < _nPatients; j++) {
                Patient patObjCopy = (Patient)_baselinePatients[j].Clone();
                Patient patObjCopyTwo = (Patient)patObjCopy.Clone();
                patObjCopy.PatientCovariates[EXAMPLE_CYCLE].Add("Covariate for patient ",    // To mark the arm name and make the patient struct different
                                                                j.ToString() + 
                                                                " in arm " + 
                                                                i.ToString());

                // Save the patient copy in the _patientsCurrentArm WITHOUT changing the patient in _baselinePatients
                _patientsCurrentArm.TryAdd(j, patObjCopy);
            }
        }
    }

    internal struct Patient : ICloneable
    {
        private readonly int _seed; // used when the object is copied to regenerated the Crn
        public readonly  Random Crn { get; }

        /// <summary>
        /// Cycle, covariate name, covariate value
        /// </summary>
        public Dictionary<int,
                          Dictionary<string,
                                     string>> PatientCovariates
        { get; set; }


        /// <summary>
        /// Initiates PatientCovariates
        /// </summary>
        public Patient(int seed)
        {
            _seed = seed;
            Crn = new(_seed);
            PatientCovariates = new();
        }

        /// <summary>
        /// Clone patients
        /// </summary>
        /// <returns></returns>
        public readonly object Clone()
        {
            Patient patient = new() {
                // Here, I also want to regenerate the Crn by using _seed, as was done when the patient was constructed

                PatientCovariates = this.PatientCovariates.ToDictionary(
                    entry => entry.Key,
                    entry => entry.Value.ToDictionary(
                        innerEntry => innerEntry.Key,
                        innerEntry => innerEntry.Value
                    )
            )
            };
            return patient;
        }
    }
}
7
  • 2
    You want the exact same Crn object referenced, or you want to recreate a new one? For the former, why can't you have a separate private constructor that's only used by the Clone function? For the latter you can use the existing constructor. Commented Feb 20 at 23:16
  • @Charlieface I want to recrate a new one that is exactly the same as the original one that was originally created. Commented Feb 20 at 23:17
  • 1
    @Charlieface Recreate a new one with the same seed value. Commented Feb 21 at 0:11
  • 1
    What is the actual use case? It sounds like the context is medical, but using a Dictionary<int, Dictionary<string, string>> rather than some domain specific type is a bit of a code smell. I fail to understand the purpose of Crn, and there are several other things that seem odd. Perhaps there is some better design for your problem? You generally want your types to have behaviors, and not just being a collection of public properties. Commented Feb 21 at 9:08
  • @JonasH The context is medical. The patient is used with a random object based on a seed value for certain covariates that are generated for the specific patient. After this patient is generated, it is used in two different settings: one with treatment and one without. Hence, the Crn (common random numbers) must be the same over the treatment arms. I want to generate the patient for t = 0 (baseline) and the clone the patient twice: one instance where a treatment is given and one where it is not given. Hence, I need the Crn not to be changed by another instance after I clone the patient. Commented Feb 21 at 9:39

1 Answer 1

0

Thanks to @Charlieface, I found a solution. I can just use the existing constructor and make Random Crn being readonly.

public readonly object Clone()
{
    Patient patient = new(_seed) {
        PatientCovariates = this.PatientCovariates.ToDictionary(
            entry => entry.Key,
            entry => entry.Value.ToDictionary(
                innerEntry => innerEntry.Key,
                innerEntry => innerEntry.Value
            )
    )
    };
    return patient;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.