C#, Java and other languages have the same behaviour when it comes to reference types.

public class SomeClass {
   public string someField;
}

var instance1 = new SomeClass(); // instance1 is a reference to an object in memory
var instance2 = instance1;       // instance2 is a copy of the reference
instance2.someField = "changed";
instance1.someField == instace2.someField  // -> true
instace2 = new SomeClass();
instance2.someField = "changed again";
instance1.someField != instance2.someField // -> true -> they are different objects
instance1.someField;                       // -> "changed" -> nothing changed

The dot symbol after the variable name (instance1 or instance2) accesses the actual
object referenced by that variable. So before the dot, we have a variable referencing an object, and
after the dot we have the actual object.

instance1.someField;

Means: get reference instace1, then access the object, then access someField

Passing objects to functions has exactly the same behaviour, function parameters behave like variables assigned to the original arguments.

public static void SomeMethod(SomeClass arg1){
   arg1.someField = "changed";
}

var instance1 = new SomeClass();
SomeMethod(instance1);
instance1.someField; // -> "changed" -> field has changed

public static void OtherMethod(SomeClass arg1){
   arg1 = new SomeClass();
}

var instance1 = new SomeClass();
instance1.someField = "changed";
OtherMethod(instance1);
instance1.someField; // -> "changed" -> nothing changed

Instances of SomeClass are mutable because the value of someField may be changed.
This mutation may happen mistakenly as a result of an uncontrolled access to the object via some copy of its reference, causing unexpected side effects like defects and memory leaks.
As long as the application code can reach an object – has some reference to it – the garbage collector can’t free the memory allocated for that object. Short version of our desktop app architecture as an example:

public static class EventBus{
    private static ISet subscribers = new HashSet();
    public void AddSubscriber(Subscriber subscriber){
        subscribers.Add(subscriber);
    }
    ...
}

public class View{
   public ViewModel ViewModel;

   public View(ViewModel viewModel){
      ViewModel = viewModel;
   }
   public void Init(){
      EventBus.AddSubscriber(ViewModel);
   }
}

The life cycle of the View instance is controlled by the framework, not by us. It may create a new instance every time the view is shown on screen and destroy the instance as it disappears. However we are adding a reference
to the static list of subscribers in the EventBus. As long as the subscribers list is not flushed, the garbage collector won’t be able to set memory free for ViewModel and View instances, even though the view may not be even displayed. Opening that view many times will increase the memory consumption every time, that is a memory leak. In this particular case we unsubscribe the instance from the bus before hiding the view:

public class View{
   public ViewModel ViewModel;

   public View(ViewModel viewModel){
      ViewModel = viewModel;
   }
   public void Init(){
      EventBus.AddSubscriber(ViewModel);
   }
   public void Clear(){
      EventBus.RemoveSubscriber(ViewModel);
   }
}

In the case of the bus there isn’t much we can do to avoid having two references to the same object in two different places, we have to be aware of this behavior. In C# there is the concept of Weak Reference but as far as I know we can’t use it on WinRT (tablets).

In some other cases though we may avoid side effects:

  • Avoid more than one reference per object, avoid state
  • Keep variables local, avoid instance variables (fields)
  • When the object is a value object, design it to be immutable
  • In the case of collections, use ReadOnlyCollection when they must keep their size
  • If the object can’t be designed immutable but you need to avoid state changes at all cost, clone the object returning a deep copy of it

We may be tempted to clone objects every time someone asks for a reference to them. However this may not be possible (like with the EventBus) or it may be too expensive and complex. I’d say that cloning is the last alternative and perhaps the need for it is a design smell. Who is responsible for ensuring that object references are not causing memory leaks? It boils down to the “less surprise” principle. We should design interfaces (methods) in such a way that it’s obvious how references and state are going to be managed. If it looks like the consumer (the one asking for the reference) will not be aware of it and the consumer will likely make undesired changes to the object, then cloning the object could be a good defensive approach. But I would rather try to think how to make the API more expressive considering context and level of abstraction. I assume that the caller understands how references work.

If you, dear reader, provide some code examples I will be able to clarify my point with code. I’ll update this post if I come up with some snippets.