Consider the following short code example with a public getter and a private setter:
public class Foo
{
public class Bar
{
...
}
public Bar fooBar { get; private set; }
public int valueType { get; private set; }
}
I want to make sure that the class members can only be written to from inside the Foo
class. That works for value types like valueType
in the example above. But how do reference types like the nested class fooBar
behave?
Can I use the reference which is returned by the public getter, to manipulate my private member?
If the type you're referring to is mutable, then yes, anyone with a reference to the "container" can fetch a reference and then mutate the object. For example:
using System;
using System.Collections.Generic;
class Container
{
public List<string> List { get; private set; }
= new List<string>();
}
class Program
{
static void Main()
{
var container = new Container();
var list = container.List;
Console.WriteLine(list.Count); //0
container.List.Add("foo");
Console.WriteLine(list.Count); // 1
}
}
Here the List<string>
is being mutated outside Container
. One option to avoid this would be to use a read-only view over the mutable data:
using System;
using System.Collections.Generic;
class Container
{
private readonly List<string> list = new List<string>();
public IReadOnlyList<string> ListView { get; }
public Container()
{
ListView = list.AsReadOnly();
}
public void AddItem(string item)
{
list.Add(item);
}
}
class Program
{
static void Main()
{
var container = new Container();
Console.WriteLine(container.ListView.Count); //0
// container.ListView.Add("foo"); // Compile-time error
container.AddItem("foo");
Console.WriteLine(container.ListView.Count); // 1
}
}
Note that you shouldn't just return the list directly from the property, even if the compile-time type is IReadOnlyList<T>
- because then a caller could just cast back to List<T>
and mutate it. List<T>.AsReadOnly()
returns a genuinely read-only wrapper object around the list, so callers really won't be able to mutate it.