3

Not long ago I got familiar with with operator. Based on MSDN, when using the "with expression", reference types will be copied, but that logic can be changed by overriding copy constructor.

In the case of a reference-type member, only the reference to a member instance is copied when an operand is copied. Both the copy and original operand have access to the same reference-type instance. If you need to customize the record copy semantics, explicitly declare a copy constructor with the desired behavior.

This is how copy logic can be changed:

record WithOperatorTest()
{
    private int _myPrivateField;

    public int MyProperty { get; set; }

    public List<int> MyReferenceTypeProperty { get; set; }

    protected WithOperatorTest(WithOperatorTest original)
    {
        _myPrivateField = original._myPrivateField;
        MyPublicField = original.MyPublicField;
        MyProperty = original.MyProperty;
        // Creating new reference
        MyReferenceTypeProperty = new List<int>(original.MyReferenceTypeProperty);
    }
}

I wonder if it's somehow possible to use "with" operator inside a copy constructor to not write unnecessary code & use benefits of the operator to override only the logic that needs to be overridden? I'd love to achieve a behavior like this:

protected WithOperatorTest(WithOperatorTest original)
{
    return original with { MyReferenceTypeProperty = new List<int>(original.MyReferenceTypeProperty) };
}

Or:

protected WithOperatorTest(WithOperatorTest original)
{
   this = original with { MyReferenceTypeProperty = new List<int>(original.MyReferenceTypeProperty) };
}

Or:

protected WithOperatorTest(WithOperatorTest original) with
{
    MyReferenceTypeProperty = new List<int>(original.MyReferenceTypeProperty);
}

All the attempts above, of course, do not compile. My question is whether the is currently a way to achieve the desired behavior or we need to write copy constructors in "the old way"?

David Oganov
  • 976
  • 1
  • 11
  • 23
  • 1
    Unfortunately, I only know of an ugly workaround, not of a "nice" solution: The workaround would be to split your class into a base class (containing the fields you want copied) and a derived class (containing the fields you want to handle separately) and only override the copy constructor in the derived class. A similar example can be found here: https://stackoverflow.com/a/66151756/87698 – Heinzi Oct 21 '21 at 09:29
  • @Heinzi, thanks for sharing. Definately a possible solution, but yeah I am seeking for something more elegant, without the necessity to inherit from some other class. Most probably, there's no such feature in C# yet, but I'm not sure. – David Oganov Oct 21 '21 at 09:39
  • 3
    It's kind of circular. You need the copy constructor for `with` to work. Therefore, you cannot implement the copy constructor in terms of `with` because then nobody actually provides an implementation. – Damien_The_Unbeliever Oct 21 '21 at 10:00
  • 1
    @DavidOganov if you use sharplab.io to see the generated code you'll see that `with` calls the generated `Clone` method which in turn calls the copy constructor. If you used `with` in your copy constructor you'll end up with infinite recursion – Panagiotis Kanavos Oct 21 '21 at 10:02
  • @Damien_The_Unbeliever , PanagiotisKanavos, good points guys. Thank you. I believe for this to work there should be some syntax sugar in the language, which is not there yet :/ – David Oganov Oct 21 '21 at 10:04

0 Answers0