C# Properties with programming examples
Description:
C# Properties:- in this article, I am going to show you how the properties concept works in c# programming with step by step program explanation
C# Properties
C# Properties, like indexers, play a huge role in C#. C# version 3 introduced a simplified form of defining a property as well as a new way of creating an object and initializing it from its properties, which we will present later.
Property is used as a field of a class but actually causes a function to be called. One or two functions, called “accessors”, can be associated with the property:
- getter function for reading access to the property;
- setter function for initializing or modifying the property.
If the setter function is absent, the property is read-only.
Example: how to use Properties in c# Programming:
Let’s take an example to illustrate the C# Properties. The entered price of a product (Price property) is multiplied by two when the quantity in stock is less than ten units. Ownership has the advantage to be as easy to use as a variable while having the power of a function call. These are also the C# Properties that allow you to write expressions such as DateTime.Now.DayOfYear. We will comment on the program thereafter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
using System; using System.Collections.Generic; using System.IO; public class Product { public Product (int q, int p) { m_Qtity = q; m_Price = p; } public void Entry (int qty) { m_Qtity += qty; } public void Output (int qty) { m_Qtity -= qty; } int m_Qtity; int m_Price; public int Price // property Price { get { return m_Qtity < 10 ? m_Price * 2 : m_Price; } set { m_Price = value; } } static void Main() { Product p = new Product(8, 100); p.Entry(15); p.Output(10); // five products in stock Console.WriteLine("Current unit price:" + p.Price); Console.ReadKey(); } } |
Output:
Price is a property of the Product class. When performing:
1 |
n = p.Price; |
the read accessor function (get part) of the property is automatically called and n takes the value returned by this function. When performing:
1 |
p.Price = 50; |
the write access function (set part) of the property is executed, with value (reserved word) which automatically takes the value 50.
Nothing prevents a property from being labeled static. It can then only use fields and static methods of the class, including the static constructor for initializing the property. Such a property can be used without having to create an object of the class (do not forget to prefix the name of the property with the name of the class).
Since version 2, a property accessor can be qualified as protected or public (which is the default case). For example :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class A { public string Prop { get {.....} protected set {.....} } } |
It is possible to read the Prop property of an object from classes outside A. The modification is still possible from member functions of class A.
C# Properties are widely used and often without any code other than:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Pers { string mName; // private field public string Name { get {return mName;} set {mName = value;} } } |
C# version 3 (Visual Studio 2008) therefore introduced a simplified syntax, which only applies to this simple but nevertheless common case:
1 2 3 4 5 6 7 8 9 |
class Pers { public string Name {get; set; } ..... } |
We speak in this case of self-implemented property.
The compiler automatically generates the private field corresponding to the property (but this one remains inaccessible by your C# code) as well as the (simple) instructions corresponding to the get and the set. If you need more elaborate instructions (even only in the get or the set), there It is up to you to write the property “old fashioned”.
In the process, C# version 3 introduced a handy way to create an object (whatever the way, simplified or not, to write the property):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Pers { public string Name {get; set; } public int Age {get; set; } } ..... Pers p = new Pers {Name = "Fawad khan", Age = 26}; |
The order of the C# Properties does not matter. Parentheses (constructor) can be specified, which does not change anything to the generated code:
1 |
Pers p = new Pers () {Name = "Fawad khan", Age = 26}; |
Parentheses are optional if the constructor with no argument is ultimately called (as a reminder, in the absence of an explicitly specified constructor, a default constructor, without argument, is automatically generated).
This technique (with or without parentheses) eliminates the need for the constructor, but the latter can always be specified. In the presence of a constructor, it is always called before the initialization of C# Properties.
The technique can be applied to structures. Thus, a Rectangle can be created by:
1 2 3 4 5 6 7 8 9 |
Rectangle rc = new Rectangle {X = 10, Y = 20, Width = 30, Height = 40}; More generally : struct S {public int A, B;} ..... S s = new S {B = 10, A = 20}; |
The set part of a property can be called private. In this case, it cannot be initialized that in a function of the class, including the constructor. For example :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Pers { public int ID {get; private set; } public string NAME {get; set; } public Pers (int aID) {ID = aID;} } ..... Pers p = new Pers (5) {NAME = "xyz"}; |
We have seen how to initialize an object from its properties. Things are simpler again for nested C# Properties. For example :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Pers { public string Name {get; set; } public int Age {get; set; } Loc address = new Address (); public Loc address {get {return loc;}} } class Address { public string City {get; set; } public string Street {get; set; } } |
A Pers object can be created and initialized by:
1 2 3 |
Pers obj = new Pers {Name = "abc", Age = 28, Loc = {City = "Islamabad", address = "Pakistan"}}; |
Example2: How to make a Telephone directory using C# properties concept:
defines a telephone list. In the class phone list the variables are first name, last name, area code and number private agreed. Then the C# Properties first name, Last name, area code, number, and phone defined that enable access from outside.
The get and set routines regulate the access to the properties. In the set routines, values are entered using the keyword pass value.
First name and surname have get and set and can therefore be queried and set. Area code and number can only be set and the telephone can only be queried. The get routine of the property telephone sets prefix, a slash, and number combined into a single string. In order to it is clear that C# Properties affect the appearance of class members can change. You can also use this for this after changing a class, the usual appearance to maintain.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
using System; using System.Collections.Generic; using System.IO; public class PropertiesExample { public PropertiesExample() { telephoneList t1 = new telephoneList("Fawad","khan","0333","9537499"); telephoneList t2 = new telephoneList("", "", "", ""); t2.firstName = "abc"; t2.surName = "xyz"; t2.PreFix = "0123"; t2.Number = "4599999"; Console.WriteLine("{0}\t{1}\t{2}", t1.firstName, t1.surName, t1.phone); Console.WriteLine("{0}\t{1}\t{2}", t2.firstName, t2.surName, t2.phone); Console.ReadKey(); } static void Main() { new PropertiesExample(); } class telephoneList { private string FirstName = ""; private string Surname = ""; private string prefix = ""; private string number = ""; public string firstName { get { return FirstName; } set { FirstName = value; } } public string surName { get { return Surname; } set { Surname = value; } } public string PreFix { set { prefix = value; } } public string Number { set { number = value; } } public string phone { get { return prefix +"/"+ number; } } public telephoneList(string firstName, string surname, string prefix, string number) { this.firstName = firstName; this.surName = surname; this.prefix = prefix; this.number = number; } } } |
Output:
C# Properties without parameters:
Many types define status information that can be read or change. Often this state information is implemented by type fields. Here, for example, a type definition with two fields:
1 2 3 4 5 6 7 |
public sealed class Employee { public String Name; // Employee name public Int32 Age; // Employee age } |
By creating an instance of this type, you can get or set any information about its state using code like this:
1 2 3 4 5 6 7 |
Employee e = new Employee (); e.Name = "Fawad khan"; // Set the name of the employee e.Age = 26; // Set the age of the employee Console.WriteLine (e.Name); // Display "Fawad khan " |
This way of reading and writing object state information is very common. strange. However, I believe that an implementation of this kind is completely unacceptable. One of the cornerstones of object-oriented programming and development is data encapsulation. Data encapsulation means that type fields should never be shared with others, as this it is too easy to write code that can mess up the state information object through improper use of fields. For example, with the following code a developer can easily corrupt the Employee object:
e.Age = -5; // Can you imagine a person who is minus 5 years old?
There are other reasons for encapsulating access to data fields of a type. Before let’s say you need access to the field in order to do something, place in the cache some second value or create some kind of internal object, the creation of which was deferred, and accessing the field must not violate thread safety. Or, say the field is boolean and its value is not represented by bytes in memory, but is calculated by some algorithm.
Each of these reasons forces, when developing types, firstly to mark all fields as private, secondly, give the user your type the ability to obtain and set information about the state through special methods designed exclusively for this. Methods that perform functions wrappers for accessing a field, commonly referred to as accessors. Accessor methods can perform additional checks, ensuring that object state information will never be corrupted. I rewrote the class from the previous example as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public sealed class Employee { private String m_Name; private Int32 m_Age; public String GetName() { return(m_Name); } public void SetName(String value) { m_Name = value; } public Int32 GetAge() { return(m_Age); } public void SetAge(Int32 value) { if (value < 0) throw new ArgumentOutOfRangeException("value", value.ToString(), "The value must be greater than or equal to 0"); m_Age = value; } } |
Despite its simplicity, this example demonstrates a huge advantage. encapsulation of data fields. It also shows how easy it is to create C# properties, read-only or write-only – just omit one from accessor methods.
As you can see, data encapsulation has two drawbacks: firstly, due to the implementation for additional methods, you have to write a longer code, secondly, instead of simply referencing the field name, users of the type have to call relevant methods:
1 2 3 4 5 6 7 8 9 10 11 |
e.SetName ("Fawad khan"); // Update employee name String EmployeeName = e.GetName (); // Get the age of the employee e.SetAge (26); // Update employee age e.SetAge (-5); // Throw an exception // ArgumentOutOfRangeException Int32 EmployeeAge = e.GetAge (); // Get the age of the employee |
Personally, I find these disadvantages to be minor. However, the CLR has supported a mechanism of C# properties that partially compensates for the first drawback and completely eliminating the second.
The next class is functionally identical to the previous one, but it uses properties that are:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public sealed class Employee { private String m_Name; private Int32 m_Age; public String Name { get {return (m_Name); } set {m_Name = value; } // Keyword value } // identifies the new value public Int32 Age { get {return (m_Age); } set { if (value <0) // The value keyword is always // identifies the new value throw new ArgumentOutOfRangeException ("value", value.ToString (), "The value must be greater than or equal to 0"); m_Age = value; } } } |
As you can see, while the properties make it a bit more difficult to define the type, the additional This work is more than justified because it allows you to write the following code kind:
1 2 3 4 5 6 7 8 9 10 11 |
e.Name = "Fawad khan"; // "Set" the name of the employee String EmployeeName = e.Name; // "Get" the employee's name e.Age = 26; // "Set" the age of the employee e.Age = -5; // Throw an exception // ArgumentOutOfRangeException Int32 EmployeeAge = e.Age; // "Get" the age of the employee |
You can think of properties as “smart” fields, that is, fields with additional logic. CLR supports static, instance, abstract, and virtual al properties. In addition, properties can be marked with an access modifier and defined in the interfaces. Each property has a name and type (but not void). You cannot overload properties (that is, define multiple properties with the same name but different types).
When defining a property, they usually describe a pair of methods: get and set. However, by omitting the set method, you can define a read-only property, and by omitting the get method only, we will get a write-only property.
The get and set methods of a property manipulate a private field quite often, defined in the type. This field is commonly referred to as the backing field. But get and set methods do not have to access the backing field. For example, the type System.Threading.Thread maintains a Priority property that interacts directly from the OS, and the Thread object does not support the field holding the priority flow. Another example of properties that do not have fallback fields is immutable run-time properties: the length of the null-terminated array or the area of a rectangle specified by width and height, and so on.
When defining a property, the compiler generates and places in the resulting the following managed module:
- property get method is generated only if a method is defined for the property get access;
- the set method of a property is generated only if a method is defined for the property set access;
- A property definition is always generated in the metadata of a managed module.
Let’s go back to the Employee type shown earlier. When compiling it, the compiler detects the Name and Age properties. Since both have get and set accessors, the compiler generates four method definitions on the Employee type. Result from it turns out as if the type were originally written like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
public sealed class Employee { private String m_Name; private Int32 m_Age; public String get_Name () { return m_Name; } public void set_Name (String value) { m_Name = value; // The value argument always identifies the new value } public Int32 get_Age () { return m_Age; } public void set_Age (Int32 value) { if (value <0) {// value always identifies a new value throw new ArgumentOutOfRangeException ("value", value.ToString (), "The value must be greater than or equal to 0"); } m_Age = value; } } |
The compiler automatically generates the names of these methods by adding a get_ or set_ bet on the property name as specified by the developer.
Property support is built into C#. Finding code trying to get or set a property, the compiler generates a call to the corresponding method. If the language used does not directly support properties, you can still access their access by calling the desired accessor method. The effect is the same, only the original text looks less elegant.
Besides the accessor methods, for each of the properties defined in the original text, compilers generate an entry in the metadata of the managed unit with the definition of the property. Such an entry contains several flags and a property type, as well as references to get and set accessors. This information exists only then, to associate the abstract concept of “property” with its accessor methods. Compilers and other tools can use this metadata through the class System.Reflection.PropertyInfo. And yet the CLR does not use this metadata, requiring only accessor methods when executed.
Auto-implemented properties in C#:
If it is necessary to create C# properties to encapsulate the backing fields, then in C# there is a simplified syntax called auto-implemented properties (Automatically Implemented Properties, AIP). Here’s an example for the Name property:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public sealed class Employee { // This property is automatically implemented public String Name {get; set; } private Int32 m_Age; public Int32 Age { get {return (m_Age); } set { if (value <0) // value always identifies a new value throw new ArgumentOutOfRangeException ("value", value.ToString (), "The value must be greater than or equal to 0"); m_Age = value; } } } |
If you declare properties and do not provide implementations for set and get methods, then the C# compiler will automatically declare them as private fields. In this example, the field will be of type String – the type of the property. And the compiler automatically implements calls the get_Name and set_Name methods to correctly return the value from the field and assigning a value to the field.
You may ask why this is necessary, especially in comparison with a regular ad string field Name? There is a big difference between the two. Using AIP syntax means that you are creating a property. Any program code that has accessing this property calls get and set methods. If you later decide to implement these methods yourself, replacing their implementation suggested compiler by default, then the code that has access to the property will not need to recompile. However, if you declare Name as a field and later replace it property, then all the program code that has access to the field will have to be recompile as it will access the methods of the property. I personally don’t like auto-implemented properties, usually, I try avoid them for several reasons.
- The syntax for declaring a field can include initialization, thus you declare and initialize a field in one line of code. However, there is no suitable syntax for setting the initial value using AIP. Therefore, you must implicitly initialize all auto-implemented properties in all constructors.
- The runtime serialization engine stores the field name in the serialized stream. The name of the fallback field for the AIP is determined by the compiler, and it can change this name every time it compiles the code, negating the ability to deserialize instances of all types containing automatically realizable properties. Do not use this mechanism for types subject to serialization and deserialization.
- During debugging, you cannot set a breakpoint in the AIP set and get methods, therefore, you won’t be able to easily know when the application gets and sets the value of the auto-implemented property. Breakpoints can be set only in those properties that the programmer writes himself.
You should also be aware that when using AIP, the properties must be at the level of read/write access because the compiler generates set and get methods. It reasonable as reading and write fields are useless without being able to read the values, moreover, readable fields are useless if they only store default value. In addition, due to the fact that you do not know the name automatically generated fallback field, your code should always refer to the property by name. And if you choose to explicitly implement one of the accessor methods, then you will have to explicitly implement both accessors and not use AIP at the same time. The AIP mechanism works too uncompromisingly.
C# Properties and Debugger in Visual Studio:
Microsoft Visual Studio allows you to specify the C# properties of objects in the viewport debugger. As a result, when setting a breakpoint, the debugger will call the get method and show the return value. This can be helpful when searching errors, but can also affect the accuracy and performance of the application. For example, suppose you created a FileStream for a file being streamed over the network, and then added the FileStream.Length property to the debugger viewport. Everyone once upon hitting the breakpoint, the debugger will invoke the get accessor, which in the internal implementation will make a network request to the server to get the current file length!
Likewise, if a get accessor produces some side effect, then this effect will always be performed when the point is reached. stop. For example, if the get accessor increments the counter every time call time, then this counter will increment each time at the breakpoint. Because of these potential issues, Visual Studio allows you to disable the calculations for the properties specified in the debugger viewport. To do this,
Click on Tools and select Options,
After click the option a new window will be opened, in that window click on Debugging and select General and uncheck Enable Property Evaluation And Other Implicit Function Calls (see below figure). And press the ok button.