C# Fields, Properties and Indexers

In C#, a field is a variable which is declared directly in a class or struct in C#. A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field.

 1 public class MyClass
 2 {
 3     // this is a field.  It is private to your class and stores the actual data.
 4     private string _myField;
 5 
 6     // this is a property. When accessed it uses the underlying field,
 7     // but only exposes the contract, which will not be affected by the underlying field
 8     public string MyProperty
 9     {
10         get
11         {
12             return _myField;
13         }
14         set
15         {
16             _myField = value;
17         }
18     }
19 
20     // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
21     // used to generate a private field for you
22     public int AnotherProperty { get; set;} 
23 }

If you are a beginner, you might get confused between a C# field and a C# property. You can store value using either a field or a property and retrieve the value back. You can even protect both fields and properties using access modifiers such as private or protected. So you might wonder, why we need to have property when you can achieve the same using field or vice-versa?

But,

Object orientated programming principles say that, the internal workings of a class should be hidden from the outside world. If you expose a field you’re in essence exposing the internal implementation of the class.

Therefore we wrap fields with Properties (or methods in Java’s case) to give us the ability to change the implementation without breaking code depending on us.

So,

Properties expose fields. Fields should (almost always) be kept private to a class and accessed via get and set properties. Properties provide a level of abstraction allowing you to change the fields while not affecting the external way they are accessed by the things that use your class.

In this article, we will discuss about C# Fields, Properties and Indexers.

Contents

C# Fields

Fields are variables associated with either classes or instances of classes. There are seven modifiers which can be used in their declarations. These include the four access modifiers ‘public’, ‘protected’, ‘internal’ and ‘private’ (discussed in C# Class) and the ‘new’ keyword (discussed in C# Polymorphism). The three remaining modifiers are:

C# Static

By default, fields are associated with class instances. Use of the ‘static’ keyword, however, associates a field with a class itself, so there will only ever be one such field per class, regardless of the number of the class instances (and the static field will exist even if there are no class instances).

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         //the 'NoOfInstances' field will exist even if there are no 'MyClass' instances
 6         Console.WriteLine("No of MyClass instances (Before): " + MyClass.NoOfInstances);
 7         for (int i = 0; i < 5; i++)
 8         {
 9             var myClass = new MyClass();
10         }
11         Console.WriteLine("No of MyClass instances (After): " + MyClass.NoOfInstances);
12         Console.ReadLine();            
13         /*
14         Output:
15         No of MyClass instances (Before): 0
16         No of MyClass instances (After): 5
17         */
18     }
19 }
20 
21 public class MyClass
22 {
23     public static int NoOfInstances = 0;
24 
25     public MyClass()
26     {
27         //there will only ever be one 'NoOfInstances' field, 
28         //regardless of the number of the 'MyClass' instances
29         MyClass.NoOfInstances = MyClass.NoOfInstances + 1;
30     }
31 }

C# Readonly

Where a field is readonly, its value can be set only once, either in the class declaration, or in the class constructor (for static fields this will be static constructor). The following code example (which, please note, deliberately doesn’t compile) shows both cases: the field StaticReadonlyInt is set in the class declaration; the field readonlyString is set in the class constructor.

 1 public class MyClass
 2 {
 3     public static readonly float pi = 3.14f; // a static readonly field
 4     public readonly float gravityOnEarth = 9.8f; // a readonly field
 5 
 6     static MyClass() //this is a static constructor
 7     {
 8         pi = 3.1417f;
 9     }
10 
11     public MyClass()
12     {
13         pi = 2f; //this will not compile
14         gravityOnEarth = 9.80665f;
15     }
16    
17     public void DoSomething()
18     {
19         gravityOnEarth = 2f; //this will not compile
20     }
21 }

Also,

While we’re on declarations, note also that a field declaration can involve multiple fields, as in the following line of code

1 public static int a = 1, b, c = 2;

which is equivalent to

1 public static int a = 1;
2 public static int b;
3 public static int c = 2;

C# Constants

Constants are unchanging types, associated with classes, that are accessible at compile time. Because of this latter fact, constants can only be value types rather than reference types. Constant declarations take the ‘const’ keyword (not ‘static’, even though they are associated with classes), and the five modifiers ‘public’, ‘protected’, ‘internal’, ‘private’ and ‘new’.

1 public const int area = 4;
 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         Console.WriteLine(MyClass.area);
 6         MyClass.area = 5; //this will not compile
 7     }
 8 
 9     public class MyClass
10     {
11         public const int area = 4;
12         public MyClass()
13         {
14             MyClass.area = MyClass.area + 1; //this will not compile
15         }
16     }
17 }

If you’ve been reading carefully, you may be struck by the thought: what’s the difference between declaring a field as ‘const’ and declaring a field ‘static readonly’. Good question. The general point is that static readonly fields can be reference types as well as value types. However the main intention is to allows the class designer to remove write privilege of attributes that are intended to be set only during construction, even from methods of the target class (see Private class data pattern).

C# Properties

Properties can be thought of as ‘virtual’ fields. From the outside, a class’ property looks just like a field. But from the inside, the property is generated using the actual class fields.

Property declarations take just those modifiers taken by methods (see C# Method Modifiers) Unlike languages like Java, C# provides dedicated support for accession and mutation of these properties. Suppose, for instance, that a type contains an internal field called ‘age’. With the following code one could specify a property Age, providing accessors and mutators to this internal field.

 1 public int Age
 2 {
 3     get
 4     {
 5         return this.age;
 6     }
 7     set
 8     {
 9         this.age = value;
10     }
11 }

Notice that the term ‘value’ is used in the above piece of code. This variable always holds the value passed to the ‘set’ block. For instance, the execution of the following line of code (assuming the appropriate class instance) would automatically set ‘value’ in the ‘set’ block to 4.

1 person.Age = 4;

This property Age can be described as ‘read-write’ since it can be both read from and written to. To make a property ‘write-only’ one simply does not specify a ‘get’ block; to make it ‘read-only’ one does not specify a ‘set’ block. The following piece of code demonstrates the read-only property ‘Adult’:

 1 public bool Adult
 2 {
 3     get
 4     {
 5         if (this.age<18)
 6             return false;
 7         else
 8             return true;
 9     }
10 }

C# Indexers

If properties are ‘virtual fields’, indexers are more like ‘virtual arrays’. They allow a class to emulate an array, where the elements of this array are actually dynamically generated by function calls.

The following piece of code defines a class to hold a list of runners in an athletics race. The runners are held in lane order, and an indexer is exposed which allows the list to be both read from and written to. The indexer deals gracefully with cases in which the lane number passed to it is either too high or too low.

 1 class RaceDetails
 2 {
 3     private string[] lanes;
 4 
 5     public RaceDetails()
 6     {
 7         this.lanes = new string[8];
 8     }
 9 
10     public string this[int i]
11     {
12         get
13         {
14             return (i>=0 && i<8) ? this.lanes[i] : "error";
15         }
16 
17         set
18         {
19             if (i>=0 && i<8) this.lanes[i] = value;
20         }
21     }
22 }

The following simple code illustrates use being made of the class just defined. The name of the person in the race’s first lane is set, and then this name is sent to a console window.

1 RaceDetails rd = new RaceDetails();
2 rd[0] = "fred";
3 Console.WriteLine("Lane One : " + rd[0]);

As can be seen from the example, an indexer is defined in a similar way to a property. One important difference is in the indexer’s signature; the word ‘this’ is used in place of a name, and after this word indexing elements are provided.

Indexers aren’t differentiated by name, and a class cannot declare two indexers with the same signature. However, this does not entail that a class is limited to just one indexer. Different indexers can have different types and numbers of indexing elements (these being equivalent to method parameters, except that each indexer must have at least one indexing element, and the ‘ref’ and ‘out’ modifiers cannot be used).

Because indexing elements are not limited to integers, the original description of indexers as ‘virtual arrays’ actually rather undersells them. For example, where the indexing elements include strings, indexers present themselves more like hash tables.

The following code shows an implementation for the RaceDetails class of an indexer whose indexing element is a string. Using this indexer it is possible to refer to a lane using the name of the person currently filling that lane.

 1 public string this[string s]
 2 {
 3     get
 4     {
 5         int laneNum = getCorrespondingLane(s);
 6         return (laneNum<0) ? "error" : this.lanes[laneNum];
 7     }
 8 
 9     set
10     {
11         int laneNum = getCorrespondingLane(s);
12         if (laneNum>=0) this.lanes[laneNum] = value;
13     }
14 }
15 
16 
17 private int getCorrespondingLane(string myName)
18 {
19     for (int x=0; x<lanes.Length; x++)
20     {
21         if (myName==lanes[x]) return x;
22     }
23     return -1;
24 }

The following piece of code gives an example of the kind of use one might make of this string indexer.

1 rd[5] = "fred";
2 rd["fred"] = "jill";
3 Console.WriteLine(rd[5]); //Displays jill
C# Fields, Properties and Indexers
Share this

Subscribe to Code with Shadman