Properties, Array and Indexers in C#

Properties are generally used to encapsulate fields of a class. What if a property returns an array, that way we expose an array as property. That may result in accidently overwrite a lot of data as array are reference types. Let’s understand the whole scenario with an example:

Following structure exposes an array property named details.

  1. struct Person  
  2. {  
  3.    private string[] details;  
  4.    public string[] Details  
  5.    {  
  6.       get { return this.details; }  
  7.       set { this.details = value; }  
  8.    }  
  9. }  
Usage:
  1. Person p = new Person();  
  2. string [] details = new string[]{ "James","Kavin","Ramy" };  
  3. p.Details = details;  
Consequences:
  1. string[] refdetails = p.Details;  
  2. refdetails[0] = "James Modified";  
  3. refdetails[1] = "Kavin Modified"  
  4. refdetails[2] = "Ramy Modified";  
Because array are reference types, the variable refdetails refers to the same object as private data variable in the Person structure. Any changes made to the elements in refdetails are made to the details directly. However, this problem can be solved by using Clone method in the get and set accessors of the Details property as shown below:
  1. struct Person  
  2. {  
  3.    private string[] details;  
  4.    public string[] Details  
  5.    {  
  6.       get { return this.details.Clone() as string[]; }  
  7.       set { this.details = value.Clone() as string[]; }  
  8.    }  
  9. }   
From the memory usage point of view, the described approach is quite expensive and messy.

Other Options:

Usage of Indexers, explained in my previous articles, is the better solution in this case i.e. don’t expose the entire array as a property rather make its individual element accessible through an Indexer.
  1. struct Person  
  2. {  
  3.     private string[] details;  
  4.     public string this[int i]  
  5.     {  
  6.         get { return this.details[i]; }  
  7.         set { this.details[i] = value; }  
  8.     }  
  9. }  
The code below uses the indexer in a similar manner as described earlier with Properties:
  1. Person p = new Person();  
  2. string [] details = new string[]{ "James","Kavin","Ramy" };  
  3. p.Details = details;  
  4. Assignment:  
  5. string[] refdetails = new string[3];  
  6. refdetails[0] = p[0];  
  7. refdetails[1] = p[1];  
  8. refdetails[2] = p[2];  
  9. Modifying:  
  10. refdetails[0] = "James Modified";  
  11. refdetails[1] = "Kavin Modified"  
  12. refdetails[2] = "Ramy Modified";  
The advantage with indexers is that changing values in refdetails array has no effect on the original array. If you really want to modify elements in the Person class, use the statement as shown below:
  1. p[0] = "James Modified";  
  2. p[1] = "Kavin Modified"  
  3. p[2] = "Ramy Modified";