-1

I was just wondering what is considered the best practice when assigning reference type properties, and under no circumstances do I want them to share instance of the object (I want a deep copy).

Let's say I have a class:

public class GeoLocation : SomeBase, ICloneable // Only contains value type properties
{
  public double AValueTypeProperty { get; set; }

  public GeoLocation Clone()
  {
    return new GeoLocation{ AValueTypeProperty = this.AValueTypeProperty };
  }

  object ICloneable.Clone()
  {
    return Clone();
  }
}

This class is used as a property by several other classes:

public class PointOfInterest
{
  public GeoLocation Location { get; set; }
  // Other members
}

public class SomeOtherTypeOfPoint
{
  public GeoLocation Location { get; set; }
  // Other members
}

What I want to avoid is for people to write a function that makes these classes share a GeoLocation instance, when they only want to copy it. As work will be done on those point classes independently and we don't want them to affect eachother.

If I want to assign the Location value (and only that value) from one of them to the other as a new copy of GeoLocation, one way to do it is to clone.

Let's say a developer needs to write this gibberish function to move a point to the same location as another point, but not have them affect each others location by later processing.

public void MovePointOfInterestToSomeOtherTypeOfPoint(PointOfInterest poi, SomeOtherTypeOfPoint other)
{
  poi.Location = other.Location.Clone();
}

The above seems a bit error prone in my case as we always want a copy, and if someone forgets to write ".Clone()" here it can cause some unfortunate side effects.

Or is it normal to clone in the setter for Pop in both classes? As in:

public class PointOfInterest
{
  private GeoLocation _loc = null;
  public GeoLocation Location { get => _loc; set => _loc = value.Clone(); }
  // Other members
}

Which I'm not terribly fond of, as it seems I need a private field for this to work, but at least it seems safer than hoping developers don't forget to clone.

Alternatively, in C++ I'm used to be able to create classes on the stack and treated similarly to what is called value types in C#, is there any way to achieve the same in C#. I wish to use inheritance, so structs aren't exactly what I'm looking for.

Thanks in advance.

  • I didn't understand what exactly you are looking for. Can you please elaborate more? Are you looking for shallow or deep copy in C#? – Salah Akbari Apr 01 '20 at 14:24
  • @SalahAkbari Sorry, I've updated the question. – OneRaccoonToRuleThemAll Apr 01 '20 at 14:28
  • Then you may find this helpful https://stackoverflow.com/questions/18066429/shallow-copy-or-deep-copy – Salah Akbari Apr 01 '20 at 14:30
  • You can define your own Copy/ Clone method to create a copy of the object. Another approach is to create a constructor that accepts an object of your class to create a clone. – Sandeep Apr 01 '20 at 14:33
  • @SalahAkbari Sorry, I think there is a bit of a misunderstanding, I see that I forgot to add a crucial bit of information to my question. PopularClass has a custom deep copy implementation of Clone(). My question is if I have to use that clone method everywhere, which I feel is quite prone to error if I forget it, or there are other methods that are better. Sorry, my wording is colored by my lack of experience with the language. – OneRaccoonToRuleThemAll Apr 01 '20 at 14:36
  • @Sandeep The clone stategy is what I have outlined in the first suggestion, but it feels incredibly error prone, same with a constructor. But thanks for the feedback. – OneRaccoonToRuleThemAll Apr 01 '20 at 14:47
  • In the context of a unit of work (operation/ web request) I see no reason why you would need to produce copies of objects considering that they are immutable, thread-safe objects. In case they aren't immutable, it seems odd to have different instances of it dangling around, instead I'd structure my operation in a way to reduce the usage scope of this object/entity. – Thomas C. G. de Vilhena Apr 01 '20 at 14:57
  • @ThomasC.G.deVilhena They are in this case completely independent pieces of mutable data. I'll try to update the post with a more intuitive example. – OneRaccoonToRuleThemAll Apr 01 '20 at 15:23

2 Answers2

1

My personal preference is to avoid the situation by using immutable classes whenever possible. Then it does not matter if the object is shared, since it cannot be changed anyway.

There are some variations on full immutability and other patterns:

  • 'Popsicle' immutability - where the object can be changed up to a point, and then frozen.
  • ReadOnly interface - the owner of the object can mutate whatever it wants, but only shares an interface that is read-only.
  • Wrapping a immutable object in a mutable container. Users who want the current instance can extract the object, users who want the latest instance can share the container.

This might not be practical for all kinds of types, in some cases mutable classes simply fit the domain model better. But if you find that you need to clone objects frequently there should be some better way to model the problem to avoid much of the cloning.

More reasons why to make objects immutable

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • Thanks. The PointOfInterest is supposed to be altered in the function in the example (these are just mock functions as I cant share actual code), so itself can't be immutable. There will also be independent processing on these point types afterwards that may alter their location, so they can't point to the same GeoLocation instance when that happens. Maybe a copy-on-write pattern would be better in my case? – OneRaccoonToRuleThemAll Apr 01 '20 at 15:46
  • Processing can be done by creating a new object with the desired changes. This may be cumbersome for large objects, but is fairly easy for small objects (like a point). – JonasH Apr 01 '20 at 18:22
1

From your implementation details it seems you need to:

  • Manage mutable data objects with only value type properties
  • Reference these objects around with each parent having its own copy of it

With that in mind you could take advantage of Structure types:

Structure types have value semantics. That is, a variable of a structure type contains an instance of the type. By default, variable values are copied on assignment, passing an argument to a method, and returning a method result

This way you won't need to manage creating copies of your objects, it will be performed transparently on variable assignments.

Thomas C. G. de Vilhena
  • 13,819
  • 3
  • 50
  • 44
  • I was hoping to avoid this, as the type (GeoLocation in this example) needs to satisfy an interface. But thanks for the reply! – OneRaccoonToRuleThemAll Apr 01 '20 at 17:41
  • Then, from your requirements, I see no other option than manually copying objects upon assignment. The [MemberwiseClone Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.memberwiseclone?view=netframework-4.8) should be sufficient for that, since your object has only value type properties. Cheers! – Thomas C. G. de Vilhena Apr 01 '20 at 17:54
  • Structs/valuetypes are a great idea, but *mutable* structs is generally a bad idea since it is very easy to mutate the wrong copy of the struct. – JonasH Apr 01 '20 at 18:31
  • Great point @JonasH. Mutable structures should be handled with caution. There is a nice overview here: https://stackoverflow.com/questions/441309/why-are-mutable-structs-evil – Thomas C. G. de Vilhena Apr 01 '20 at 21:39