• Because properties are implemented with methods, adding multithreaded support is easier. You can enhance the implementation of the get and set accessors to provide synchronized access to the data:


      1. public class Customer 
      2.     private object syncHandle = new object(); 
      3.     private string name; 
      4.     public string Name 
      5.     { 
      6.         get 
      7.         { 
      8.             lock (syncHandle) 
      9.                 return name; 
      10.         } 
      11.         set 
      12.         { 
      13.             if (string.IsNullOrEmpty(value)) 
      14.                 throw new ArgumentException( 
      15.                 "Name cannot be blank"
      16.                 "Name"); 
      17.             lock (syncHandle) 
      18.                 name = value; 
      19.         } 
      20.     } 
      21.     // More Elided. 
  • Properties have all the language features of methods. Properties can be virtual:

      1. public class Customer 
      2.     public virtual string Name 
      3.     { 
      4.         get
      5.         set
      6.     } 
  • You can extend properties to be abstract and define properties as part of an interface definition

    1. public interface INameValuePair<T> 
    2.     string Name 
    3.     { 
    4.         get
    5.     } 
    6.     T Value 
    7.     { 
    8.         get
    9.         set
    10.     } 
  • The property syntax extends beyond simple data fields. If your type should contain indexed items as part of its interface, you can use indexers (which are parameterized properties).

      1. public int this[int index] 
      2.     get { return theValues[index]; } 
      3.     set { theValues[index] = value; } 
      4. // Accessing an indexer: 
      5. int val = someObject[i]; 

    Indexers can be virtual or abstract, can be declared in interfaces, and can be read-only or read-write.

    Indexers can use noninteger parameters to define maps and dictionaries


      1. public Address this[string name]  
      2. {  
      3.     get { return adressValues[name]; }  
      4.     set { adressValues[name] = value; }  
      5. }  

    In keeping with the multidimensional arrays in C#, you can create multidimensional indexers, with similar or different types on each axis:


      1. public int this[int x, int y] 
      2.     get { return ComputeValue(x, y); } 
      3. public int this[int x, string name] 
      4.     get { return ComputeValue(x, name); } 

    Notice that all indexers are declared with the this keyword. You cannot name an indexer in C#. Therefore, every different indexer in a type must have distinct parameter lists to avoid ambiguity.

  • Property accessors should live up to users' expectations
  • Get accessors should not have observable side effects. Set accessors do modify the state, and users should be able to see those changes. It should not have performance characteristics that are significantly different than a simple data access. Property accessors should not perform lengthy computations, or make cross-application calls (such as perform database queries), or do other lengthy operations that would be  inconsistent with your users’expectations for a property accessor.