Академический Документы
Профессиональный Документы
Культура Документы
Properties are a natural extension to fields. Very few programming languages support the notion
of a property. Unlike a variable, a property is not stored in a memory location. It is made up of
functions. Thus even though a property and a field share the same syntax a property has the
advantage that code gets called. When we initialize a variable, no code in our class gets called.
We are not able to execute any code for a variable access or initialization at all. In the case of a
property, we can execute tons of code. This is one singular reason for the popularity of a product
like Visual Basic - the use of properties. One simple example is setting the value of a variable. If
it is through a variable, we have no control over the value used. If the same access is through a
property, the programmer has no inkling of whether it is a property or a variable, we can build
range checks to make sure that the variable does not cross certain bounds.
Lets start by creating a simple property. A property is a member of a class. It behaves like a
variable for the user.
a.cs
public class aa
public int ff {
}
Compiler Error
a.cs(9,12): error CS0548: ‘aa.ff’ : property or indexer must have at least one accessor
We have tried to create a property called ff which is of type int. We get an error because a
property is used either on the left or the right of an equal to sign. If we had created a variable ff,
we would like to write a statement as gg = ff + 9. Here ff should return some value which is of
the data type int.
a.cs
aa a = new aa();
int gg = a.ff + 9;
System.Console.WriteLine(gg);
public class aa
public int ff {
get
System.Console.WriteLine(“in get”);
return 12;
Output
in get
21
A property should have at least one accessor, in our case, a get as we want to read the value of
the property. Thus a.ff calls the get accessor which returns an int, in this case 12. If we did not
have access to the code of the class aa, we would have assumed ff to have been a variable.
a.cs
aa a = new aa();
a.ff = 19;
System.Console.WriteLine(a.ff);
public class aa
public int ff {
get
{
System.Console.WriteLine(“in get”);
return 12;
set
System.Console.WriteLine(value);
Output
19
in get
12
A variable can also be used on the left-hand side of the equalto sign. In this case we are writing
or changing the value of the variable. We are passing it some value. If it is a property, ff in our
case, a.ff = 19 will call the accessor set. The set accessor has a free variable available in it called
value. It gets created automatically, we do not create this variable. In our case, this has the value
19, which we are displaying in WriteLine. Then to display the value of the property ff, the get
needs to be called again. The get always returns the same answer as the set does not store the
value of the variable anywhere. To resolve this issue, we do the following.
a.cs
{
aa a = new aa();
a.ff = 19;
System.Console.WriteLine(a.ff);
public class aa
int f1;
public int ff {
get
System.Console.WriteLine(“in get”);
return f1;
set
f1 = value;
Output
in set 19
in get
19
To implement a property in real life, we create a public variable which will hold the value of the
property. This variable f1 will have the same data type as the property i.e. an int in our case. In
the get, we return f1 and in the set we initialize f1 to value. This is the simplest case possible.
The reason we use a property and not a variable is because if we change the value of a
variable/field, then code in our class is not aware of the change. Also we have no control over
what values the variable will contain. The user can change them to whatever he/she likes and we
cannot implement range checks on the variable. Also the user may want to associate some action
with the changes in the value of the variable. Using a property, reading or writing to the variable
also can be monitored.
a.cs
aa a = new aa();
a.ff = 19;
System.Console.WriteLine(a.ff);
public class aa
int f1;
public int ff {
get
{
System.Console.WriteLine(“in get”);
return f1;
Compiler Error
a.cs(6,1): error CS0200: Property or indexer ‘aa.ff’ cannot be assigned to — it is read only
You are allowed to declare a property readonly by omitting the set accessor. No one is now
allowed to change the value of the property. It now behaves as a const or readonly field.
a.cs
aa a = new aa();
a.ff = 19;
public class aa
int f1;
public int ff {
set
{
System.Console.WriteLine(“in set “ + value);
f1 = value;
Output
in set 19
Theoretically, you can have a property which is write only i.e. only with a set accessor. With set,
you can change the value of ff but it is of limited use because you can never access the value of
ff. A property differs from a field by ending with {}.
a.cs
public class aa
public int ff {
set
}
public int ff {
get
Compiler Error
a.cs(12,12): error CS0102: The class ‘aa’ already contains a definition for ‘ff’
You cannot create a property in 2 separate bits and pieces. It has to be in one whole. This is part
of the syntax. The above creates two properties, both called ff, the first one being write only, the
second, read only. The compiler tells you that you cannot create two properties by the same
name.
a.cs
public class aa
public int ff {
get {
}
set {
Compiler Error
a.cs(10,12): error CS0102: The class ‘aa’ already contains a definition for ‘ff’
You obviously cannot have a property and variable with the same name. The compiler would not
know whether to invoke the property or the field. They both are stored in the same namespace.
a.cs
class zzz
yyy.i = 20;
System.Console.WriteLine(yyy.i);
class yyy
get {
System.Console.WriteLine(“get”);
return 10;
}
set {
System.Console.WriteLine(“set “ + value);
Output
set 20
get
10
The rules of static apply to properties also. Like variable we access them using the class and not
the instance. Everything that we have learned about static in the past applies to properties also.
a.cs
class zzz
a.i = 100;
System.Console.WriteLine(a.i);
{
public abstract int i
get ;
set ;
get
System.Console.WriteLine(“get”);
return 10;
set
System.Console.WriteLine(“set “ + value);
Output
set 100
get
10
The abstract property i in class xxx carries no code at all. The get and set accessors are simply
represented by a semicolon. In the derived class, we must implement both the get and the set
accessors. If we do not use the override keyword, it is new. We hope you have finally understood
new and override.
a.cs
class zzz
get ;
get
}
set
Compiler Error
a.cs(20,1): error CS0546: ‘yyy.i.set’: cannot override because ‘xxx.i’ does not have an
overridable set accessor
In class xxx, the abstract property has only a get accessor. In the derived class we are
implementing both the get and the set. The original never ever had a set. This is unacceptable to
the compiler. Thus we have no choice but to implement only the accessors that are present in the
original. A get accessor can be viewed as a method which returns a value but accepts no
parameters.
a.cs
class yyy
public void i {
Compiler Error
a.cs(3,13): error CS0547: ‘i’ : property or indexer cannot have void type
It makes no sense for an accessor to have a void type as a variable cannot be of type void. Void
literally means ‘I do not know the type’ or no type at all.
a.cs
class yyy
{
public int i {
set
return 10;
Compiler Error
a.cs(6,2): error CS0127: Since ‘yyy.i.set’ returns void, a return keyword must not be followed by
an object expression
A set accessor can be viewed as function which returns void but accepts one parameter which
stands for the value of the property. Thus a set cannot return a value. If we remove the 10, we
will not get an error.
a.cs
class zzz
public int i {
set
value = 20;
}
}
The reserved variable value in the set can be changed at will. Though, understanding why
anyone would want to do such dumb stuff is beyond us.
a.cs
class zzz
public int i {
set
int value;
Compiler Error
a.cs(9,6): error CS0136: A local variable named ‘value’ cannot be declared in this scope because
it would give a different meaning to ‘value’, which is already used in a ‘parent or current’ scope
to denote something else
We cannot however create a variable value as it will clash with the variable value which is
already present by default in the set.
a.cs
class zzz
{
public static void Main()
a.i = 10;
((yyy)b).i = 20;
b.i = 10;
class yyy
public int i {
set {
public int i {
get {
return 10;
}}
Compiler Error
a.cs(9,1): error CS0200: Property or indexer ‘xxx.i’ cannot be assigned to — it is read only
In the class yyy, the property i has only the set accessor. In the class xxx which derives from yyy,
we have implemented only the get accessor. The property i in class xxx hides the i of yyy. They
do not add up. What we are trying to say is that both these properties are independent of each
other. What we had thought C# would have done is, taken the set from one class and added it to
the second. However, that does not make sense. It treats them independently. If we want to use
the property of the class yyy, then we need to explicitly cast it as we have done for b. Thus the
property i of class yyy gets hidden but can be accessed.
A property is not necessarily slower than a variable. A variable access normally initializes some
memory, whereas a property executes a method. This is not necessarily slower as at times, C#
will rewrite your property methods to memory accesses. This is called inlining of code. Except
for minor differences, all that we mentioned about virtual, abstract and new apply also to a
property. The difference is, if the original property has a get and a set, the derived class will only
implement a set or a get.
Indexers
a.cs
a[1] = 10;
Compiler Error
a.cs(6,1): error CS0021: Cannot apply indexing with [] to an expression of type ‘yyy’
We have created an object a that looks like yyy. The object a, in no sense of the word is an array.
We are assuming that a is an array and we’ve used the array syntax a[], hence it gives us an error.
a.cs
a[1] = 10;
set {
Output
in get 10 1
We’ve added a few lines to have the array notation work with an object that looks like yyy. To
implement indexers, we need to create a special property called this. This is a reserved word. As
of now, we have a parameter i (an int) in the square brackets. When we did properties earlier,we
learnt that a set gets called whenever we want to initialize or set a variable. Within the set
accessor we have a special variable called value which stores the value passed to the set, in this
case 10. The variable i will hold the value 1 as the array parameter is 1.
a.cs
System.Console.WriteLine(a[1]);
set
get
{
System.Console.WriteLine(“in set “ + i);
return 23;
Output
in set 1
23
The rules binding properties are applicabe to indexers too. When you want to read the value of
a[1], the get gets called. The major difference between properties and indexers is that when you
implement the code for indexers you have to understand that the get and set get called with a
variable which is the array parameter value. The code will have to understand array simulation.
a.cs
a[“hi”] = 30;
System.Console.WriteLine(a[“hi”]);
public int z;
public int this[string i]
set
z = value;
get
return z;
Output
In get 30 hi
In set hi
30
The this property has a return value, in this case, an int. Also the [] brackets can contain data
types other than an int. In this case a string. The string i has a value hi as that is what we passed
in the array brackets. You can have two this’s in your class. You have to decide what data type to
use in the array brackets. An indexer is very useful when you have a database object and you
want to access the data in the fields using a notation [“fieldname”]
a.cs
class zzz
a[1] = 10;
a[“one”] = 10;
a[“hi”,2] = 30;
class yyy
set
set
{
System.Console.WriteLine(“one string “+ i + “ “ + value);
set
Output
one int 1 10
The signature of an indexer is the number and types of formal parameters. The return value and
the names of the parameters do not contribute to the indexers signature. Thus we have
overloaded the indexers to take an int, string or a string int combination. Each time a different
function gets called. The point to understand is that all the indexers have to return the same data
type, in our case int. The same rules that apply to function overloading apply here also.
Functions cannot differ only by return values. We are sure that for indexers in the next version,
C# should/must make an exception.
A property is identified by its name, an indexer by its signature. There is no concept of property
overloading in C#.
a.cs
class zzz
{
public static void Main()
class yyy
set
Compiler Error
a.cs(9,19): error CS0106: The modifier ‘static’ is not valid for this item
A property can be both an instance member which is the default or static. An indexer
unfortunately can only be an instance member and not static. God alone knows why this
discrimination against indexers. Once again no rational reason for the above error. Obviously
you cannot create a variable with the same name as that of the parameter passed in the indexer.
a.cs
class zzz
System.Console.WriteLine(a[2]);
class yyy
get
return 20;
set
{
get
int p = base[i];
return 200;
set
base[i] = value;
Output
xxx set 20 2
yyy set 20 2
yyy get 2
xxx get 2 20
200
The above example deals with calling the indexers of the base class. At times when we are
overriding code in the derived class, we would like to call the original indexer in the base class
first. The first rule that we have to adhere to is that the indexer in the base class must be declared
virtual. In the derived class, we are now declaring it with the modifier override. Same rules as
above. In the set accessor, we have to call the original as base[i], where i is the index to the
indexer. Also we need to pass it the value to initialize itself. This is stored in the variable value.
This a[2] in Main gets replaced by base[2] in the set. In get the reverse takes place. Here we need
to place base[i] on the right of the equalto sign, the original get will return a value, in this case
20, which we are storing in a variable p. What we do with p as well as the value from the get is
our business.
a.cs
class yyy
get
return 10;
set
return 20
Compiler Error
a.cs(5,1): error CS0111: Class ‘yyy’ already defines a member called ‘get_Item’ with the same
parameter types
a.cs(9,1): error CS0111: Class ‘yyy’ already defines a member called ‘set_Item’ with the same
parameter types
Like a property, an indexer also gets a name change. If people can get their bodies pierced then
why cannot a indexer get converted to a series of functions starting with get? For a get, the
parameters are the same as we pass to an indexer. It has a return value and the type of the
indexer. Also the set has one more added parameter and that is the free variable value.