Be careful when returning C# arrays that are private members of an object, as it essentially makes the array contents public, since the client can easily change the array.
For example, here is a simple object “MyObject” that stores a private array of strings. It essentially makes those strings public by returning the private array in the “GetArray” method:
public class MyObject { public MyObject() { this.m_MyArray = new string[2]; this.m_MyArray[0] = "hello"; this.m_MyArray[1] = "goodbye"; } private string[] m_MyArray; public string[] GetArray() { return this.m_MyArray; } public override string ToString() { string s = String.Empty; foreach (string x in this.m_MyArray) { s += x + " "; } return s; } }
Simple Console Example
This simple console program shows what can go wrong. The client gets the private array, then modifies one of its strings:
class Program { static void Main( string[] args ) { MyObject obj = new MyObject(); Console.WriteLine( obj ); string[] array = obj.GetArray(); array[0] = "ALOHA"; Console.WriteLine( obj ); Console.ReadLine(); } }
The console output shows the object’s private array has been changed externally:
hello goodbye
ALOHA goodbye
Of course it’s possible that you might want this behavior. However, it’s preferred to use a C# collection instead of an array when clients are allowed to freely add and remove items.
Array Reference is Still Private
Note that the client cannot resize the array or replace it with another array. That’s because MyObject’s reference to the array is still private and hence inaccessible to clients.
A Better Way
To ensure your array contents remain private, return a copy of the array:
public string[] GetArray() { return (string[])this.m_MyArray.Clone(); }
Note this makes a shallow clone of the array. If you want the objects referenced by the array to also remain private, i.e., you do not want clients to have access to the referenced objects, you need to make a deep clone. See this article on object cloning for more information.
I like that but deep clone can be expensive.
You can also use List which has a AsReadOnly() method, both methods enforces readonly on runtime.
You can also expose your collection as IEnumerable and enforce readonly at compiletime (although I don’t like dealing with IEnumerable, it has a very poor API). You can read more about those issues here: http://www.dev102.com/2008/04/10/how-to-expose-your-collections-safely/
System.Collections.ObjectModel.ReadOnlyCollection(Of T) is the class for this purpose. Has array-like semantics (including random access by this[int index]).
Don’t leave home without it 🙂