User Tools

Site Tools


notes:csharp:properties

Properties and Indexers in C#

  • Properties provide a window into object's state.
  • Use implicit properties as much as possible. They are often inlined.
  • If you include any logic, it should be simple such as data validation in setters or simple computations in getters.
  • Do not throw exceptions in your properties.

Properties

  • The getter should not have any side effects.
  • You cannot pass a property to a method using the ref or out keyword.
  • You cannot use implicit properties on types that are decorated with the Serializable attribute.
  • When the JIT compiler inlines property accessors, the performance of data members and properties is the same.
  • Properties and data members are not binary compatible. It means that you have to recompile all code that uses the public data member when you change it to a public property.
  • Property accessors should not perform lengthy computations or perform database queries.

Indexers

  • Use indexers to return items from a sequence or a dictionary. You can think of indexers as parametrized properties.
  • You can define multiple indexers in a class, each with parameters of different types.
  • Single-dimension indexers with numeric parameters can participate in data binding.
  • You can't create implicit indexers as you can with properties.

Caching

  • When the getter is called occasionally, you can use the Lazy<T> class to retrieve the value only when needed.
  • When the getter is used often and when it's valid to cache the value, you can load it in the ctor and use the cached value as the property return value.
  • In all other cases when the property does not behave like a property (e.g., calls a database in the getter), use methods to manage cached values.

A virtual property:

public class Person
{
    public virtual string Name
    {
        get;
        set;
    }
}

A property in a generic interface:

public interface INameValuePair<T>
{
    string Name { get; }
    T Value { get; set; }
}

A property with synchronized access to data:

public class Person
{
    private object locker = new object();
 
    // The private field 'name' is called a backing store.
    private string name;
    public string Name
    {
        get
        {
            lock(locker)
                return name;
        }
        set
        {
            lock(locker)
                name = value;
        }
    }
}

A property with lazy call to a database in the getter. We avoid the work of retrieving the value when it's not needed. On the other hand, the first call to the property has to call the database:

public class Something
{
    private Lazy<string> obj;
 
    // ctor
    public Something()
    {
        obj = new Lazy<string>(() = RetrieveStringFromDatabase()); 
    }
 
    public string Obj => obj.Value;
}

A simple indexer:

class Something
{
    private int[] values = new int[50];
 
    public int this[int index]
    {
        get => values[index];
        set => values[index] = value;
    }
}
 
// Accesing the indexer.
var obj = new Something();
...
int v = obj[i]; 

An indexer accepting an integer and returning a string:

class Tagline
{
    string[] words = "One ring to rule them all".Split();
 
    public string this [int n]
    {
        get
        {
            if (n < 0 || n > words.length-1)
                throw new IndexOutOfRangeException("Index out of range.");
            else
                return words[n];
        }
 
        set
        {
            words[n] = value;
        }
    }
}
...
// Accesing the indexer.
var s = new Tagline();
Console.WriteLine(s[3]); // displays the word "rule"

An indexer accepting a non-integer parameter. This indexer defines a map:

class Company
{
    private Dictionary<string, Person> employees;
 
    public Person this[string name]
    {
        get => employees[name];
        set => employees[name] = value;
    }
}
 
// Accesing the indexer.
var comp = new Company();
...
Person m = comp["Matylda"]; 

Multidimensional indexers with the same or different types of parameters:

public string this [int x, int y]
{
    get { ... }
    set { ... }
}
 
public string this [int i, string name]
{
    get { ... }
    set { ... }
}
notes/csharp/properties.txt · Last modified: 2020/08/26 (external edit)