Consider the physical computer you are using. It has many properties—a size, a weight, a date it was built. Properties describe this computer.
We use properties on a class
(like a Computer class
) to describe the class
. They can be set and read from like other fields, and special code can be run.
To start, we introduce an Example class
. One field, an integer, is present—it is used as a backing store for the Number property.
int
property in the Example class
. Number provides get and set implementations.class
.using System; class Example { int _number; public int Number { get { return this._number; } set { this._number = value; } } } class Program { static void Main() { Example example = new Example(); example.Number = 5; // set { } Console.WriteLine(example.Number); // get { } } }5
We see automatically implemented property syntax in C#. A hidden field is generated—then the get and set statements are expanded to use that hidden field.
using System; class Example { public int Number { get; set; } } class Program { static void Main() { Example example = new Example(); example.Number = 8; example.Number *= 4; Console.WriteLine(example.Number); } }32
Enum
This example shows the DayOfWeek
enum
type in a property. We also insert code in the getter (or setter) that checks the backing store or the parameter value.
enum
types like DayOfWeek
. Many properties will use string
or int
.using System; class Example { DayOfWeek _day; public DayOfWeek Day { get { // We don't allow this to be used on Friday. if (this._day == DayOfWeek.Friday) { throw new Exception("Invalid access"); } return this._day; } set { this._day = value; } } } class Program { static void Main() { Example example = new Example(); example.Day = DayOfWeek.Monday; Console.WriteLine(example.Day == DayOfWeek.Monday); } }True
We make a private property. Here the IsFound
property can only be set in the Example class
. We set it in the Example constructor.
Program.Main
method by using an Example instance.using System; class Example { public Example() { // Set the private property. this.IsFound = true; } bool _found; public bool IsFound { get { return this._found; } private set { // Can only be called in this class. this._found = value; } } } class Program { static void Main() { Example example = new Example(); Console.WriteLine(example.IsFound); } }True
We can also make an entire property private. If we do this, we can only use the property in the same enclosing class
.
class
.using System; class Example { int _id; private int Id { get { return this._id; } set { this._id = value; } } public void Display() { // Access the private property in this method. this.Id = 7; Console.WriteLine(this.Id); } } class Program { static void Main() { Example example = new Example(); example.Display(); } }7
Properties can also be static
—this means they are associated with the type and not an instance. Static classes can only have static
properties.
using System; class Example { static int _count; public static int Count { get { // Side effect of this property. _count++; return _count; } } } class Program { static void Main() { Console.WriteLine(Example.Count); Console.WriteLine(Example.Count); Console.WriteLine(Example.Count); } }1 2 3
Let us consider how to make getters or setters on an automatic property. We cannot omit either the getter or setter in this kind of property.
using System; class Example { public Example() { // Use private setter in the constructor. this.Id = new Random().Next(); } public int Id { get; private set; } } class Program { static void Main() { Example example = new Example(); Console.WriteLine(example.Id); } }2077325073
Automatic properties have support for default values much like fields. Here we assign the Quantity property of Medication to 30 by default.
using System; class Medication { public int Quantity { get; set; } = 30; // Has default value. } class Program { static void Main() { Medication med = new Medication(); // The quantity is by default 30. Console.WriteLine(med.Quantity); // We can change the quantity. med.Quantity *= 2; Console.WriteLine(med.Quantity); } }30 60
We can use lambda-style syntax to specify properties. These are expression-bodied properties—we use "get" and "set" and then the result on the right side.
class Program { private static int test; public static int Test { get => test; set => test = value; } static void Main() { // Use the property. Program.Test = 200; System.Console.WriteLine(Program.Test); } }200
Suppose we wish to have a property that is not changeable (mutable) after its creation. It can only be initialized, not set.
init
" keyword to specify that the class
Test here has an Info property that can be initialized, but not set afterwards.using System; class Test { public string Info { get; init; } } class Program { static void Main() { // Use the init setter with an initializer. var test = new Test() { Info = "Ok" }; // The Info is ok. Console.WriteLine(test.Info); } }Ok
Compiler optimizations ensure that properties are efficient. These same optimizations are used on methods, which share the underlying implementation with properties.
using System; using System.Diagnostics; class Program { static string _backing; // Backing store for property. static string Property // Getter and setter. { get { return _backing; } set { _backing = value; } } static string Field; // Static field. static void Main() { const int m = 100000000; for (int x = 0; x < 10; x++) // Ten tests. { Stopwatch s1 = new Stopwatch(); s1.Start(); // Version 1: test property. for (int i = 0; i < m; i++) { Property = "string"; if (Property == "cat") { } } s1.Stop(); Stopwatch s2 = new Stopwatch(); s2.Start(); // Version 2: test field. for (int i = 0; i < m; i++) { Field = "string"; if (Field == "cat") { } } s2.Stop(); Console.WriteLine("{0},{1}", s1.ElapsedMilliseconds, s2.ElapsedMilliseconds); } } }Property get/set: 604.6 ms Field read/assign: 603.6 ms
Properties are used throughout most C# programs. They are a powerful way to replace methods. They present a more intuitive way to use objects.