Chapter 5
Data Access, Properties, and Methods

Kurt NÝrmark ©
Department of Computer Science, Aalborg University, Denmark


Abstract
Previous lecture Next lecture
Index References Contents
This lecture is about operations in classes and structs. In particular, we are concerned with operations that access the encapsulated data in a type. C# offers several different kinds of operations. Methods are the most well-known, but C# also supports properties, indexers, and overloaded operators.


Accessing Data in Objects

Indirect data access
Slide Annotated slide Contents Index
References Textbook 
Avoiding direct access to data is one of the main themes of object-oriented programming. We first introduce the idea. After that we will study properties, which - in C# - help us a lot to access data indirectly.

Data encapsulated in a class is not accessed directly from other classes

Rather, data is accessed indirectly via operations

  • Why indirect data access?

    • Protects and shields the data

      • Possible to check certain conditions each time the data is accessed

      • Possible to carry out certain actions each time the data is accessed

    • Makes it easier - in the future - to change the data representation

      • Via "compensations" programmed in the accessing operations

    • Makes it possible to avoid the allocation of storage for some data

      • Calculating instead of storing

Overview of data access in C#
Slide Annotated slide Contents Index
References Textbook 
Our interest is indirect data access. On this page we take a very broad look at data access, including direct access to data.

In C# the data of a class can be accessed in several different ways

  • Data access

    • Directly via public instance variables

      • Never do that!

    • Indirectly via properties

      • Clients cannot tell the difference between access via properties and direct access of instance variables

    • Indirectly via methods

      • Should be reserved for "calculations on objects"

    • Indirectly via indexers

      • Provides access by means of the notation known from traditional array indexing

    • Indirectly via overloaded operators

      • Provides access by means of the language-defined operator symbols


Properties

Properties - Basic Use
Slide Annotated slide Contents Index
References 

Program: A Class C with a simple properties - getter and setter.
public class C {
  
  private int v;

  public C(int t){
    v = t;
  }

  public int V {
    get  {return v;}
    set  {v = value;}
  }  
}

Program: A client of class C.
using System;
public class Client {

  public static void Main(){

    C x = new C(5);

    x.V = 7;                  // activates setter: v is assigned to 7.
    Console.WriteLine(x.V);   // activates getter: output 7.
  }

}

Properties - Tricky Use
Slide Annotated slide Contents Index
References 

Program: A Class C with a simple properties - getter and setter.
public class C {
  
  private int v;

  public C(int t){
    v = t;
  }

  public int V {
    get  {return v * 2;}
    set  {v = value + 3;}
  }  
}

Program: A client of class C.
using System;
public class Client {

  public static void Main(){

    C x = new C(5);

    x.V = 7;                  // activates setter: v is assigned to ?
    Console.WriteLine(x.V);   // activates getter: output ?
  }

}

Properties in C#
Slide Annotated slide Contents Index
References Textbook 

Properties introduce getter and setter methods in C# - in a very convenient way. You can think of a property as a method. It is important to realize, however, that you cannot tell the difference between an activation of a property and use of a variable. An activation of a method M reveal itself by the required parentheses after M: M(...).

Properties allow indirect getting and setting of instance variables

We introduce properties by a number of examples.

On this page we provide a number of introductory examples of a Balance property of class BankAccount.

Program: A BankAccount class with a trivial Balance property together with Deposit and Withdraw methods.
using System;

public class BankAccount {

   private string owner;
   private decimal balance;  
                             
   public BankAccount(string owner, decimal balance) {
      this.owner = owner; 
      this.balance = balance;
   }

   public decimal Balance {   
     get {return balance;}
   }       

   public void Deposit(decimal amount){
     balance += amount;
   } 

   public void Withdraw(decimal amount){
     balance -= amount;
   } 

   public override string ToString() { 
      return owner + "'s account holds " +
            + balance + " kroner";
   }
} 

Program: A BankAccount class with a Balance property - without a balance instance variable.
using System;

public class BankAccount {    

   private string owner;
   private decimal[] contributions;
   private int nextContribution;

   public BankAccount(string owner, decimal balance) {
      this.owner = owner; 
      contributions = new decimal[100];
      contributions[0] = balance;
      nextContribution = 1;
   }

   public decimal Balance {                           
     get {decimal result = 0;                         
          foreach(decimal ctr in contributions)       
             result += ctr;                           
          return result;                              
         }
   }    

   public void Deposit(Decimal amount){
     contributions[nextContribution] = amount;
     nextContribution++;
   } 

   public void Withdraw(Decimal amount){
     contributions[nextContribution] = -amount;
     nextContribution++;
   } 

   public override string ToString() { 
      return owner + "'s account holds " +
            + Balance + " kroner";                  
   }
} 

Program: A client program.
using System;

class C{

  public static void Main(){
    BankAccount ba = new BankAccount("Peter", 1000);
    Console.WriteLine(ba);

    ba.Deposit(100);
    Console.WriteLine("Balance: {0}", ba.Balance); 
                                                   
    ba.Withdraw(300);                              
    Console.WriteLine("Balance: {0}", ba.Balance);

    ba.Deposit(100);
    Console.WriteLine("Balance: {0}", ba.Balance);
  }

}

Program: Output from the client program.
Balance: 1100
Balance: 800
Balance: 900

Program: A BankAccount class with a disciplined Balance property.
using System;

public class BankAccount {

   private string owner;
   private decimal balance;  
   private bool readMode;    

   public BankAccount(string owner, decimal balance) {
      this.owner = owner; 
      this.balance = balance;
      this.readMode = true;
   }

   public decimal Balance {
     get {if (readMode){
             readMode = false;
             return balance;
          }
          else throw new Exception("Cannot read now!");
         }
     set {if (!readMode){
             balance = value;
             readMode = true;
          }
          else throw new Exception("Cannot write now!");
         }
   }   

   public override string ToString() {
      return owner + "'s account holds " +
            + balance + " kroner";
   }
} 

Program: A client of the disciplined BankAccount.
using System;

class C{

  public static void Main(){
    BankAccount ba = new BankAccount("Peter", 1000);             
    Console.WriteLine(ba);
    
    ba.Balance += 100;            // read balance + deposit
    Console.WriteLine(ba);
    
    ba.Balance -= 300;            // read balance + withdraw
    Console.WriteLine(ba);
    
    decimal amount = ba.Balance;  // read balance
    ba.Balance = amount + 100;    // deposit
    Console.WriteLine(ba);
    
    ba.Balance = 400;             // illegal deposit
    Console.WriteLine(ba);

  }

}

Program: Output of the this client.
Peter's account holds 1000 kroner
Peter's account holds 1100 kroner
Peter's account holds 800 kroner
Peter's account holds 900 kroner

Unhandled Exception: System.Exception: Cannot write now!
   at BankAccount.set_Balance(Decimal value)
   at C.Main()

Exercise 5.2. A funny BankAccount

In this exercises we provide a version of class BankAccount with a "funny version" of the Balance property. You should access the exercise via the web version, in order to get access to the source programs involved.

Study the Balance property of the funny version of class BankAccount.

Explain the behaviour of the given client of the funny BankAccount.

Next test-run the program and confirm your understanding of the two classes.

Please notice how difficult it is to follow the details when properties - like Balance in the given version of class BankAccount - do not pass data directly to and from the instance variables.

Read more about this topic in the text book version of this material.

Properties: Class Point with polar coordinates
Slide Annotated slide Contents Index
References Textbook 
The example on this page is a typical, real-life illustration of the usefulness of properties.

A real life illustration of properties

Program: Class Point with polar data representation. Both rectangular and polar access is provided via properties.
// A versatile version of class Point with Rotation and internal methods
// for rectangular and polar coordinates. 

using System;

public class Point {

  public enum PointRepresentation {Polar, Rectangular}

  private double r, a;            
                                  
  public Point(double x, double y){
     r = RadiusGivenXy(x,y);
     a = AngleGivenXy(x,y);
  }

  public Point(double par1, double par2, PointRepresentation pr){  
   if (pr == PointRepresentation.Polar){                           
     r = par1; a = par2;
   } 
   else {
     r = RadiusGivenXy(par1,par2);
     a = AngleGivenXy(par1,par2);
   }
  }

  public double X {                             
    get {return XGivenRadiusAngle(r,a);}        
  }

  public double Y {                             
    get {return YGivenRadiusAngle(r,a);}        
  }


  public double Radius {                        
    get {return r;}                             
  }

  public double Angle{                          
    get {return a;}                             
  }   

  public void Move(double dx, double dy){
    double x, y;
    x = XGivenRadiusAngle(r,a);   y = YGivenRadiusAngle(r,a); 
    r = RadiusGivenXy(x+dx, y+dy);
    a = AngleGivenXy(x+dx, y+dy);
  }

  public void Rotate(double angle){   
    a += angle;                       
  }                                   

  public override string ToString(){
    return  "(" + XGivenRadiusAngle(r,a) + "," + YGivenRadiusAngle(r,a) + ")";   
  }


  private static double RadiusGivenXy(double x, double y){    
    return Math.Sqrt(x * x + y * y);
  }

  private static double AngleGivenXy(double x, double y){     
    return Math.Atan2(y,x);
  }

  private static double XGivenRadiusAngle(double r, double a){  
    return r * Math.Cos(a);
  }

  private static double YGivenRadiusAngle(double r, double a){  
    return r * Math.Sin(a);
  }

  
}

Exercise 5.3. Point setters

In the Point class on the accompanying slide we have shown how to program getter properties in the class Point. Extend the four properties with setters as well. The new version of this class will support mutable points.

Write a small client program that demonstrates the use of the setter properties.

Hint: Please be aware that the revised class should allow us to get and set the rectangular and polar coordinates (x, y, angle, radius) of a point independent of each other. You should first consider what it means to do so.

As a matter of notation, it is not possible to tell the difference between direct access of an instance variable and access via a property

Read more about this topic in the text book version of this material.

Automatic Properties
Slide Annotated slide Contents Index
References Textbook 

In C# 3.0 it is possible to automatize the definition of trivial getter and setter properties

Program: Class BankAccount with two automatic properties.
using System;

public class BankAccount{

  // automatic generation of private instance variables

  public BankAccount(string owner, decimal balance){
    this.Owner = owner; 
    this.Balance = balance; 
  }

  public string Owner {get; set;}

  public decimal Balance {get; set;}

  public override string ToString(){
    return  Owner  + "'s account holds " +  Balance  + " kroner";
  }
} 

Program: An equivalent BankAccount class without automatic properties.
using System;

public class BankAccount{

  private string _owner;
  private decimal _balance;

  public BankAccount(string owner, decimal balance){
    _owner = owner; 
    _balance = balance; 
  }

  public string Owner {
    get {return _owner;}
    set {_owner = value;}
  }

  public decimal Balance {
    get {return _balance;}
    set {_balance = value;}
  }

  public override string ToString(){
    return  Owner  + "'s account holds " +  Balance  + " kroner";
  }
} 

Program: A Client of class BankAccount.
using System;

public class Client {

  public static void Main(){
    BankAccount ba1 = new BankAccount("Bill",100);

    ba1.Owner = "James";
    ba1.Balance = 5000;

    Console.WriteLine(ba1.Owner);
    Console.WriteLine(ba1);
  }

}

Program: Output from the Client program.
James
James's account holds 5000 kroner

Automatic properties contribute to a C# 3.0 convenience layer on top of already existing means of expressions.

Object Initialization via Properties
Slide Annotated slide Contents Index
References Textbook 

In C# 3.0 properties can be used together with constructors to ease creation of new objects.

Program: Class BankAccount - as short as possible.
using System;

public class BankAccount{

  // automatic generation of private instance variables
  // default parameterless constructor

  public string Owner {get; set;}      

  public decimal Balance {get; set;}   

  public override string ToString(){
    return Owner + "'s account holds " + Balance + " kroner";     
  }                                                               
} 

Program: A client of the simple BankAccount with object initializers.
using System;

public class Client {

  public static void Main(){
    BankAccount ba1 = new BankAccount{Owner = "James", Balance = 250},
                ba2 = new BankAccount{Owner = "Bill", Balance = 1200};

    Console.WriteLine(ba1);
    Console.WriteLine(ba2);
  }

}

Program: An equivalent BankAccount class without object initializers.
using System;

public class Client {

  public static void Main(){
    BankAccount ba1 = new BankAccount();
    ba1.Owner = "James"; 
    ba1.Balance = 250;

    BankAccount ba2 = new BankAccount();
    ba2.Owner = "Bill";
    ba2.Balance = 1200;

    Console.WriteLine(ba1);
    Console.WriteLine(ba2);
  }

}

Program: Class BankAccount - with two constructors.
using System;

public class BankAccount{

  // automatic generation of private instance variables

  public BankAccount(): this("NN") {   
  }                                    
                                       
  public BankAccount(string owner){    
    this.Balance = 0;                  
    this.Owner = owner;                
  }                                    

  public string Owner {get; set;}     

  public decimal Balance {get; set;}   

  public override string ToString(){
    return Owner + "'s account holds " + Balance + " kroner";     
  }                                                               
} 

Program: A client of class BankAccount with an object initializer.
using System;

public class Client {

  public static void Main(){
    BankAccount ba1 = new BankAccount{Owner = "James", Balance = 250},   
                ba2 = new BankAccount("Bill"){Balance = 1200};           
                                                                         

    Console.WriteLine(ba1);
    Console.WriteLine(ba2);
  }

}

Program: An equivalent client of class BankAccount without object initializers.
using System;

public class Client {            
                                 
  public static void Main(){     
    BankAccount ba1 = new BankAccount();
    ba1.Owner = "James";         
    ba1.Balance = 250;           
                                 
    BankAccount ba2 = new BankAccount("Bill");
    ba2.Balance = 1200;

    Console.WriteLine(ba1);
    Console.WriteLine(ba2);
  }

}

Program: Output of the Client program.
James's account holds 250 kroner
Bill's account holds 1200 kroner

Program: Class BankAccount and class Person.
using System;

public class BankAccount{   

  public BankAccount(){
     this.Balance = 0;
     this.Owner = new Person();   
  }                               
                                  
  public Person Owner {get; set;}
  public decimal Balance {get; set;}

  public override string ToString(){
    return Owner + "'s account holds " + Balance + " kroner";
  }
} 

public class Person {    
  public string FirstName {get; set;}
  public string LastName {get; set;}

  public override string ToString(){
    return FirstName + " " + LastName;
  }  
}

Program: A client of class BankAccount with nested object initializers.
using System;

public class Client {

  public static void Main(){
    BankAccount ba1 = new BankAccount{ 
                            Owner = {FirstName = "James",       
                                     LastName = "Madsen"},      
                            Balance = 250},   

                ba2 = new BankAccount{  
                             Owner = {FirstName = "Bill",       
                                      LastName = "Jensen"},
                             Balance = 500};

    Console.WriteLine(ba1);
    Console.WriteLine(ba2);
  }

}

The use of object initializers mimics the use of keyword parameters in constructors

Summary of properties in C#
Slide Annotated slide Contents Index
References Textbook 
We mention and summarize some important properties of properties.

Syntax: The syntax of a C# property. Here we show both the getter and setter. At least one of them must be present.

 modifiers return-type property-name{
  get {body-of-get}
  set {body-of-set}
}

  • Property characteristics

    • Provides for either read-only, write-only, or read-write access

    • Both instance and class (static) properties make sense

    • Property setting appears on the left of an assignment, and in ++ and --

    • Trivial properties can be defined "automatically"

    • Properties should be fast and without unnecessary side-effects

A C# property will often have the same name as a private data member

The name of the property is capitalized - the name of the data member is not

Naming conventions - pertain to coding style.


Indexers

Indexers in C#
Slide Annotated slide Contents Index
References Textbook 
Indexers are a kind of properties. Indexers let you use array notation on objects that are instances of your own classes.

Indexers allow access to data in an object with use of array notation

Program: A Class A with an indexer. This is a simple and somewhat artificial example of the use of indexers. It is illustrated how three individual variables d, e, and f in class A can be accessed as a[1], a[2], a[3], where a is an instance of class A.
using System;

public class A {
  private double d, e, f;   

  public A(double v){
    d = e = f = v;          
  }

  public double this [int i]{
   get {                 
     switch (i){
       case 1: {return d;}     
       case 2: {return e;}     
       case 3: {return f;}     
       default: throw new Exception("Error");
     }
   }
   set {
     switch (i){
       case 1: {d = value; break;}   
       case 2: {e = value; break;}   
       case 3: {f = value; break;}   
       default: throw new Exception("Error");
    }
   }
  }             

  public override string ToString(){
    return "A: " + d + ", " + e + ", " + f;
  } 

}

Program: A client of A which uses the indexer of A.
using System;

class B {
  
  public static void Main(){
    A a = new A(5);   
    double d;

    a[1] = 6; a[2] = 7.0; a[3] = 8.0;  

    d = a[1] + a[2];   
                       

    Console.WriteLine("a: {0}, d: {1}", a, d);
  }
}

Program: Output from Main in class B.
a: A: 6, 7, 8, d: 13

Program: The class BitArray. This is example shows a fine and realistic use of an indexer. The indexer accesses the individual bits in a bit array. The bit array is represented as a (relatively small) array of 32 bit integers. This example is taken from the C# language specification. Please consult the text book version for an explanation of the details.
// From the ECMA-334 C# Language specifications (section 17.8).
// Also in Hejlsberg et al., The C# Programming Language, 2ed.

using System;
public class BitArray   
{                       
   int[] bits;   
   int length;

   public BitArray(int length) {
      if (length < 0) throw new ArgumentException();
      bits = new int[((length - 1) >> 5) + 1];  
      this.length = length;                     
   }

   public int Length {
      get { return length; }
   }

   public bool this[int index] {                     
      get {                                          
         if (index < 0 || index >= length) {         
            throw new IndexOutOfRangeException();
         }
         return (bits[index >> 5] & 1 << index) != 0;  
      }
      set {                                          
         if (index < 0 || index >= length) {         
            throw new IndexOutOfRangeException();
         }
         if (value) {                                
            bits[index >> 5] |= 1 << index;          
         }
         else {                                      
            bits[index >> 5] &= ~(1 << index);
         }
      }
   }   
}

Program: A client of class BitArray.
// From the ECMA-334 C# Language specifications (section 17.8).
// Also in Hejlsberg et al., The C# Programming Language, 2ed.

using System; 

class CountPrimes
{
   static int Count(int max) {                 
      BitArray flags = new BitArray(max + 1);  
      int count = 1;                           
      for (int i = 2; i <= max; i++) {         
         if (!flags[i]) {
            for (int j = i * 2; j <= max; j += i) flags[j] = true;
            count++;                           
         }
      }
      return count;
   }
   static void Main(string[] args) {           
      int max = int.Parse(args[0]);            
      int count = Count(max);
      Console.WriteLine("Found {0} primes between 1 and {1}", count, max);
   }
}

Reference

Associative Arrays
Slide Annotated slide Contents Index
References Textbook 
Associative arrays are generalized arrays that allow indexing via objects of an arbitrary type (not just integers). Indexers provide a natural notation for associative arrays.

The concept associative array:

An associative array is an array which allows indexing by means of arbitrary objects, not just integers

An associative arrays maps a set of objects (the indexing objects, keys) to another set of objects (the element objects).

Program: The class A indexed by a string. An example similar to one of the previous indexer examples. In this example it is illustrated how to index via objects of type string.
using System;

public class A {
  private double d, e, f;

  public A(double v){
    d = e = f = v;
  }

  public double this [string str]{
   get {
     switch (str){
       case "d": {return d;}
       case "e": {return e;}
       case "f": {return f;}
       default: throw new Exception("Error");
     }
   }
   set {
     switch (str){
       case "d": {d = value; break;}
       case "e": {e = value; break;}
       case "f": {f = value; break;}
       default: throw new Exception("Error");
    }
   }
  }   

  public override string ToString(){
    return "A: " + d + ", " + e + ", " + f;
  } 

}

Program: A client of A which uses the string indexing of A.
using System;

class B {
  
  public static void Main(){
    A a = new A(5); 
    double d;

    a["d"] = 6; a["e"] = 7.0; a["f"] = 8.0;

    d = a["e"] + a["f"];   // corresponds to d = a.d + a.e 
                           // in case d and e had been public

    Console.WriteLine("a: {0}, d: {1}", a, d);
  }
}

Program: Output from Main in class B.
a: A: 6, 7, 8, d: 15

Reference

Associative arrays are in C# implemented by means of hashtables in dictionaries

In the lecture about collections, specifically in the interface IDictionary<K,V> we will see how indexers are can be used to access objects of type V via objects of type K by use of the notation dict[k], where dict is a dictionary and k is a key of type K.

Example of associating Person with BankAccount
Slide Annotated slide Contents Index
References 

An associative array that maps Person objects to their BankAccount

Program: The class Person.
public class Person{

  private string name;

  public Person (string name){
    this.name = name;
  }

  public string Name{
    get {return name;}
    set {name = value;}
  }

  // Other methods

}

Program: The class BankAccount - without owner.
using System;

public class BankAccount {

   private double interestRate;    
   private decimal balance;        
                                   
   public BankAccount(double interestRate, decimal balance) {
      this.interestRate = interestRate;
      this.balance = balance;
   }   

   public decimal Balance () {
      return balance;
   }

   public void Withdraw (decimal amount) {
      balance -= amount;
   }

   public void Deposit (decimal amount) {
      balance += amount;
   }

   public void AddInterests() {
      balance = balance + balance * (decimal)interestRate;
   }    

   public override string ToString() {
      return "The account holds " + balance + " kroner";
   }
} 

Program: The class PersonAccountPair.
using System;

public class PersonAccountPair{     
                                    
  private Person person;            
  private BankAccount bankAccount;  

  public PersonAccountPair(Person person, BankAccount bankAccount){
    this.person = person;
    this.bankAccount = bankAccount;
  }
 
  public BankAccount Account {
    get {return bankAccount;}
    set {bankAccount = value;}
  }

  public Person Person {
    get {return person;}
    set {person = value;}
  }

}

Program: The class Accounts - the associative array class.
using System;

public class Accounts{

  private PersonAccountPair[] store;
  private int next;
  private const int LIMIT = 100;

  public Accounts(){
    store = new PersonAccountPair[LIMIT];
    next = 0;
  }

  public BankAccount this[Person p]{   
     get {                             
       int i = IndexOfPerson(p);       
       return store[i].Account;        
     }                                 
     set {
       int i = IndexOfPerson(p);
       if (i < next)
         store[i].Account = value;
       else {
         store[next] = new PersonAccountPair(p, value);
         next++;
       }
     }
  } // End indexer

  private int IndexOfPerson(Person p){
    for(int i = 0; i < next; i++){
      if (store[i].Person == p)
         return i;
    }
    return next;
  }

}

Program: A client of Accounts.
using System;

class Client{

  public static void Main(){
 
     Accounts acc = new Accounts();

     Person p1 = new Person("Peter"),
            p2 = new Person("Marie");

     acc[p1] = new BankAccount(0.02, 1000);  
     acc[p2] = new BankAccount(0.03, 5600);  

     Console.WriteLine(acc[p1]);             
                                             
  }

}

In real life, this program would be written with use of Dictionary<Person,BankAccount>

Summary of indexers in C#
Slide Annotated slide Contents Index
References Textbook 
On this slides we mention a number of characteristics of indexers in C#.

Syntax: The syntax of a C# indexer

 modifiers return-type this[formal-parameter-list]
  get {body-of-get}
  set {body-of-set}
}

  • Indexer characteristics

    • Provide for indexed read-only, write-only, or read-write access to data in objects

    • Indexers can only be instance members - not static

    • The indexing can be based on one, two or more formal parameters

    • Indexers can be overloaded

    • Indexers should be without unnecessary side-effects

    • Indexers should be fast


Methods

Methods in C#
Slide Annotated slide Contents Index
References Textbook 
Properties and indexers are new to most readers. We should be careful, however, not to forget about methods. In most object-oriented programs, most operations will be implemented as methods. In this section of the material we will discuss - and review - the method concept, local variables in methods, and parameter passing modes in C#.

Instances methods in a class C are intended to carry out operations on instances of C

Such operations modify the state of instances of C, and may also extract information from instances of C

References

Syntax: The syntax of a method in C#

modifiers return-type method-name(formal-parameter-list){
  statements
}

References

Local variables in methods
Slide Annotated slide Contents Index
References Textbook 
We start with a brief overview of local variables, and in particular their initialization compared with the initialization of instance variables contained in classes.

Variables declared in the statements part - the block - of a method are called local variables

  • Local variables:

    • May be declared anywhere in the block

      • Not necessarily in the initial part of the block

    • Can be initialized by an initializer

    • Can alternatively be declared without an initializer

      • No default value is assigned to a local variable

        • Different from instance and class variables which are given default values

      • The compiler will complain if a local variable is referred without prior assignment

Program: Local variables and instance variables - initialization and default values. In this example we illustrate differences between local variables and instance variables with respect to initialization.
using System;

class InitDemo{

  private int intInstanceVar;         
  private bool boolInstanceVar;       

  public void Operation(){
    int intLocalVar;                  
    bool boolLocalVar;                
    
    Console.WriteLine("intInstanceVar: {0}. boolInstanceVar: {1}", 
                      intInstanceVar,
                      boolInstanceVar);

    // Compile time errors:
    Console.WriteLine("intLocalVar: {0}. boolLocalVar: {1}",   
                      intLocalVar,    
                      boolLocalVar);  

  }

  public static void Main(){
    new InitDemo().Operation();
  }

}

Read more about local variables in the text book version of this material.

Parameters
Slide Annotated slide Contents Index
References Textbook 
On this page we will review the basic concepts of method parameters: formal parameters and actual parameters. We will also enumerate the different kinds of parameter passing modes.

Actual parameters occur in a call. Formal parameters occur in the method declaration. In general, actual parameters are expressions which are evaluated to arguments. Depending on the kind of parameters, the arguments are somehow associated with the formal parameters.

Reference

  • There are four different kinds of formal parameters in C#:

    • Value parameters

      • The default parameter passing mode, without use of a modifier

    • Reference parameters

      • Specified with the ref modifier

    • Output parameters

      • Specified with the out modifier

    • Parameter arrays

      • Value parameters specified with the params modifier

The parameter passing modes.

Read more about parameters in the text book version of this material.

Value Parameters
Slide Annotated slide Contents Index
References Textbook 
Value parameters are - by far - the most frequently used parameters of methods in C#.

Value parameters are used for input to methods

  • Value parameter passing:

    • A formal parameter corresponds to a local variable

    • A formal parameter is initialized by the corresponding argument (the value of the actual parameter expression)

      • A copy of the argument is bound to the formal parameter

    • Implicit conversions may take place

    • A formal parameter is assignable, but with no effect outside the method

How value parameters work.

Program: Methods with value parameters in class BankAccount.
using System;

public class BankAccount {

   private string owner;
   private decimal balance;  
                             
   public BankAccount(string owner, decimal balance) {
      this.owner = owner; 
      this.balance = balance;
   }

   public decimal Balance {   
     get {return balance;}
   }       

   public void Deposit(decimal amount){
     balance += amount;
   } 

   public void Withdraw(decimal amount){
     balance -= amount;
   } 

   public override string ToString() { 
      return owner + "'s account holds " +
            + balance + " kroner";
   }
} 

Assignments to a formal value parameter do not affect the corresponding actual parameter

Read more about value parameters in the text book version of this material.

Passing references as value parameters
Slide Annotated slide Contents Index
References Textbook 
Be warned! This is not a discussion of C# reference parameters. It is a discussion of how to pass references via value parameters.

Care must be taken if we pass references as value parameters

Program: The class Date and the method DayDifference with a value parameter. This class introduces the DayDifference method, which accepts a formal Date parameter.
public class Date{    
  private int year, month, day;

  public Date(int year, int month, int day){
    this.year = year; this.month = month; this.day = day;
  }

  public int Year{
    get{return year;}
    set{year = value;}
  }

  public int Month{
    get{return month;}
    set{month = value;}
  }

  public int Day{
    get{return day;}
    set{day = value;}
  }

  public int DayDifference(Date other){
    other.year++;   
    return ...;     
  }

  public override string ToString(){
    return string.Format("{0}.{1}.{2}",day, month, year);
  }

}

Program: The class Person which calls DayDifference on dateOfBirth. We pass a reference to a Date object as an actual parameter.
public class Person{

  private string name;
  private Date dateOfBirth, dateOfDeath;

  public Person (string name, Date dateOfBirth){
    this.name = name;
    this.dateOfBirth = dateOfBirth;
    this.dateOfDeath = null;
  }

  public string Name{
    get {return name;}
  }

  public Date DateOfBirth{
    get {return dateOfBirth;}
  }

  public int DayAge(){
    return new Date(2008, 3, 11).DayDifference(dateOfBirth);   
  }                                                            

  public override string ToString(){
    return "Person: " + name + " " + dateOfBirth;
  }

}

Program: A client of Person and Date which reveal the consequences. A class with a Main method which - indirectly - calls the method of interest.
using System;

class Client{

  public static void Main(){

    Person p = new Person("Hanne", new Date(1926, 12, 24));
    Console.WriteLine("{0}", p);

    int age = p.DayAge();  
                           
    Console.WriteLine("{0} of age {1}", p, age);
  }

}

Program: Client program output. The output that appears if you run the program shown above.
Person: Hanne 24.12.1926
Person: Hanne 24.12.1927 of age ...

Exercise 5.4. Passing references as ref parameters

In the Date and Person classes of the corresponding slide we pass a reference as a value parameter to method DayDifference in class Date. Be sure to understand this. Read about ref parameters later in this lecture.

Assume in this exercise that the formal parameter other in Date.DayDifference is passed by reference (as a C# ref parameter). Similarly, the actual parameter dateOfBirth to DayDifference should (of course) be passed by reference (using the keyword ref in front of the actual parameter).

What will be the difference caused by this program modification.

Test-drive the program with a suitable client to verify your answer.

In case a reference is passed as an argument to a value parameter, the referenced object can be modified through the formal parameter

This is the main point to remember from this page!

Read more about references passed by value in the text book version of this material.

Passing structs as value parameters
Slide Annotated slide Contents Index
References Textbook 
On this page we repeat the example from the previous page - but now on a struct instead of a class.

There are no surprises when we pass struct values as value parameters

Program: The struct Date and the method DayDifference with a value parameter. The exact similar setup as on the previous page.
public struct Date{                  
  private int year, month, day;

  public Date(int year, int month, int day){
    this.year = year; this.month = month; this.day = day;
  }

  public int Year{
    get{return year;}
    set{year = value;}
  }

  public int Month{
    get{return month;}
    set{month = value;}
  }

  public int Day{
    get{return day;}
    set{day = value;}
  }

  public int DayDifference(Date other){
    other.year++;        
    return ...;          
  }

  public override string ToString(){
    return string.Format("{0}.{1}.{2}",day, month, year);
  }

}

Program: The class Person which calls DayDifference on dateOfBirth.
public class Person{

  private string name;
  private Date dateOfBirth;
  private Date? dateOfDeath;

  public Person (string name, Date dateOfBirth){
    this.name = name;
    this.dateOfBirth = dateOfBirth;
    this.dateOfDeath = null;
  }

  public string Name{
    get {return name;}
  }

  public Date DateOfBirth{
    get {return dateOfBirth;}
  }

  public int DayAge(){
    return new Date(2007, 9, 25).DayDifference(dateOfBirth);   
  }                                                            

  public override string ToString(){
    return "Person: " + name + " " + dateOfBirth;
  }

}

Program: A client of Person and Date which reveal the consequences.
using System;

class Client{

  public static void Main(){

    Person p = new Person("Hanne", new Date(1926, 12, 24));
    Console.WriteLine("{0}", p);

    int age = p.DayAge();   
                            
    Console.WriteLine("{0} of age {1}", p, age);
  }

}

Program: Client program output.
Person: Hanne 24.12.1926
Person: Hanne 24.12.1926 of age ...

Exercise 5.5. Passing struct values as ref parameters

This exercise corresponds to the similar exercise on the previous slide.

In the Date struct and the Person class of this slide we pass a struct value as a value parameter to the method DayDifference.

Assume in this exercise that the formal parameter other in Date.DayDifference is passed by reference (a C# ref parameter). Similarly, the actual parameter dateOfBirth to DayDifference should (of course) be passed by reference (using the keyword ref in front of the actual parameter).

What will be the difference caused by this program modification. You should compare with the version on on the slide.

Test-drive the program with a suitable client to verify your answer.

There is a good fit between use of value types and call-by-value parameter passing

Read more about struct values passed by value in the text book version of this material.

Reference Parameters
Slide Annotated slide Contents Index
References Textbook 
Here we discuss ref parameters ala C#. This is analogous to var (variable parameters) known from Pascal.

Reference parameters can be used for both input to and output from methods

  • Reference parameter passing

    • The corresponding argument must be a variable, and it must have a value

    • The types of the formal parameter and the argument must be identical

    • The formal parameter becomes another name (an alias) of the argument

    • The actual parameter must be prefixed with the keyword ref

A formal ref parameter serve as an alias - an alternative name - of the corresponding actual parameter.

Program: The class A with a Swap method. A classical use of a reference parameter. The Swap method exchanges the values of two variables.
using System;

public class A{
  private int a, b, c;

  public A(){
    a = 1; b = 2; c = 3;
  }

  public void Swap(ref int v1, ref int v2){   
    int temp;
    temp = v1; v1 = v2; v2 = temp;
  }
 
  public override string ToString(){
    return String.Format("{0} {1} {2}", a, b, c);
  }

  public void Go(){
    Console.WriteLine("{0}", this);
    Swap(ref a, ref b); Swap(ref b, ref c);  
    Console.WriteLine("{0}", this);
  }    

  public static void Main(){
    new A().Go();
  }
}

Program: Output of class A with Swap.
1 2 3
2 3 1

Read more about reference parameters in the text book version of this material.

Output Parameters
Slide Annotated slide Contents Index
References Textbook 
out parameters in C# are reference parameters used only for output purposes.

Output parameters are used for output from methods. The method is supposed to assign values to output parameters.

  • Output parameter passing

    • The corresponding argument must be a variable

    • The corresponding argument needs not to have a value on beforehand

    • The formal parameter should/must be assigned by the method

    • The formal parameter becomes another name (an alias) of the argument

    • The types of the formal parameter and the argument must be identical

    • The actual parameter must be prefixed with the keyword out

A formal ref parameter serve as an alias - an alternative name - of the corresponding actual parameter. The formal parameter must be assigned in the method, hereby facilitating output from the method.

Program: The class A with a DoAdd method. The DoAdd method adds three value parameters and passes the result back to the caller via an out parameter.
using System;

public class A{
  private int a, b, c;
  private int r;

  public A(){
    a = 1; b = 2; c = 3;
  }

  public void DoAdd(int v1, int v2, int v3, out int v){  
    v = v1 + v2 + v3;                                    
  }
 
  public override string ToString(){
    return String.Format("{0} {1} {2}. {3}", a, b, c, r);
  }

  public void Go(){
    Console.WriteLine("{0}", this);
    DoAdd(a, b, c, out r);   
    Console.WriteLine("{0}", this);
  }    

  public static void Main(){
    new A().Go();
  }
}

Program: Output of class A with DoAdd.
1 2 3. 0
1 2 3. 6

Read more about output parameters in the text book version of this material.

Use of ref and out parameters in OOP
Slide Annotated slide Contents Index
References Textbook 
On this we discuss the usefulness of ref and out parameters in object-oriented programming.

How useful are reference and output parameters in object-oriented programming?

  • Public methods with two or more pieces of output

    • Use a number of out parameters

    • Mutate objects passed by value parameters

    • Aggregate the pieces of output in an object and return it

    • Assign the output to instance variables which subsequently can be accessed by the caller

How to handle the situation where two or more pieces of output is required from a method. Notice that out parameters provides one out of several different solutions.

ref and out parameters are relatively rare in the C# standard libraries

Read more about use of ref and out parameters in OOP in the text book version of this material.

Parameter Arrays
Slide Annotated slide Contents Index
References Textbook 
Parameter arrays in C# makes it possible to pass many different actual parameters - of the same type - to a single array parameter.

A parameter array is a formal parameter of array type which can absorb zero, one or more actual parameters

  • Parameter array passing

    • Elements of a parameter array are passed by value

    • A parameter array must be the last parameter in the formal parameter list

    • The formal parameter must be a single dimensional array

    • Arguments that follow ordinary value, ref and out parameters are put into a newly allocated array object

    • Arguments are implicitly converted to the element type of the array

Program: The class A with a DoAdd method - both out and params. A variant of the DoAdd method where all but the first parameters are summed together and returned in the first parameter, which is an out parameter.
using System;

public class A{
  private int a, b, c;
  private int r;

  public A(){
    a = 1; b = 2; c = 3;
  }

  public void DoAdd(out int v, params int[] iv){  
    v = 0;  
    foreach(int i in iv)
      v += i;
  }
 
  public override string ToString(){
    return String.Format("{0} {1} {2}. {3}", a, b, c, r);
  }

  public void Go(){
    Console.WriteLine("{0}", this);

    DoAdd(out r, a, b, c);  
    Console.WriteLine("{0}", this);

    DoAdd(out r, a, b, c, a, b, c);  
    Console.WriteLine("{0}", this);

    DoAdd(out r); 
    Console.WriteLine("{0}", this);
  }    

  public static void Main(){
    new A().Go();
  }
}

Program: Output of class A with DoAdd - both out and params.
1 2 3. 0  
1 2 3. 6  
1 2 3. 12  
1 2 3. 0  

Program: An integer sequence - use of params in constructor. It is possible to have a constructor with a parameter array.
public class IntSequence {

  private int[] sequence;

  public IntSequence(params int[] elements){
    sequence = new int[elements.Length];
    for(int i = 0; i < elements.Length; i++){
      sequence[i] = elements[i];
    }
  }

  public int? Min(){
    int theMinimum;
    if (sequence.Length == 0)
      return null;
    else {
      theMinimum = sequence[0];
      foreach(int e in sequence)    
        if (e < theMinimum)
           theMinimum = e;
    }
    return theMinimum;
  }

  public int? Max(){
    int theMaximum;
    if (sequence.Length == 0)
      return null;
    else {
      theMaximum = sequence[0];
      foreach(int e in sequence)    
        if (e > theMaximum)
           theMaximum = e;
    }
    return theMaximum;
  }

  // Other useful sequence methods

}

Reference

Read more about parameter arrays in the text book version of this material.

Extension Methods
Slide Annotated slide Contents Index
References Textbook 
Have you ever wanted to add a new method to an existing class, without defining a subclass? If so, extension methods - as introduced in C# 3.0 - is the solution to your problem.

In C# 3.0 an extension method defines an instance method in an existing class without altering the definition of the class.

Reference

Program: Motivation: A Client of Point without use of DistanceTo.
// A client of Point that instantiates three points and calculates
// the circumference of the implied triangle.

using System;

public class Application{

  public static void Main(){
    Point p1, p2, p3;
    double p1p2Dist, p2p3Dist,  p3p1Dist, circumference;

    p1 = PromptPoint("Enter first point");
    p2 = PromptPoint("Enter second point");
    p3 = PromptPoint("Enter third point");

    p1.Move(1.0, 2.0);

    p1p2Dist = Math.Sqrt((p1.x - p2.x) * (p1.x - p2.x) + 
                         (p1.y - p2.y) * (p1.y - p2.y));
    p2p3Dist = Math.Sqrt((p2.x - p3.x) * (p2.x - p3.x) + 
                         (p2.y - p3.y) * (p2.y - p3.y));
    p3p1Dist = Math.Sqrt((p3.x - p1.x) * (p3.x - p1.x) + 
                         (p3.y - p1.y) * (p3.y - p1.y));

    circumference = p1p2Dist + p2p3Dist + p3p1Dist;

    Console.WriteLine("Circumference: {0} {1} {2}: {3}", 
                       p1, p2, p3, circumference);
  }

  public static Point PromptPoint(string prompt){
    double x, y;
    Console.WriteLine(prompt);
    x = double.Parse(Console.ReadLine());
    y = double.Parse(Console.ReadLine());
    return new Point(x,y);
  }

}

Program: A Client of class Point which uses an extension method DistanceTo. The method DistanceTo is used as an instance method in this program...
// A client of Point that instantiates three points and calculates
// the circumference of the implied triangle.

using System;

public class Application{

  public static void Main(){

    Point  p1 = PromptPoint("Enter first point"),
           p2 = PromptPoint("Enter second point"),
           p3 = PromptPoint("Enter third point");

    double p1p2Dist = p1.DistanceTo(p2),   
           p2p3Dist = p2.DistanceTo(p3),   
           p3p1Dist = p3.DistanceTo(p1);   

    double circumference = p1p2Dist + p2p3Dist + p3p1Dist;

    Console.WriteLine("Circumference: {0} {1} {2}: {3}", 
                       p1, p2, p3, circumference);
  }

  public static Point PromptPoint(string prompt){
    Console.WriteLine(prompt);
    double x = double.Parse(Console.ReadLine()),
           y = double.Parse(Console.ReadLine());
    return new Point(x,y, Point.PointRepresentation.Rectangular);
  }

}

Program: The static class PointExtensions. ... but actually implemented as a (somewhat special) static method in the static class PointExtensions.
using System;

public static class PointExtensions{   

  public static double DistanceTo(this Point p1, Point p2){   
    return Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) +          
                     (p1.Y - p2.Y) * (p1.Y - p2.Y));          
  }                                                           

}

  • An extension method

    • extends the type of the first parameter

    • is defined as a static method with a this modifier on the first parameter

    • must be defined in a static class

    • cannot access private instance variables in the extended class

    • is called by - behind the scene - translating to a call of the static method

Exercise 5.6. Extending struct Double

At the accompanying page we have seen how class Point can be extended with the instance method DistanceTo. This is an extension method.

If you study the method DistanceTo you will see that we use the squareroot function Math.Sqrt, defined statically in class Math. And we could/should have used a similar Square function had it been available.

It is remarkable that C# 3.0 allows us to extend the structs behind the primitive types, such as Double and Int32.

Write a static class that extends struct Double with the two extension methods Sqrt and Square. Afterwards, rewrite the method DistanceTo such that it makes use of the new instance methods in struct Double.

Methods versus Properties versus Indexers
Slide Annotated slide Contents Index
References Textbook 
We summarize when to use methods, properties, and indexers.

Rule of thumbs for using methods, properties and indexers

  • Properties

    • For reading and extracting of individual instance/class variables

    • For writing and assigning individual instance/class variables

    • For other kinds of data access that does not involve time consuming computations

  • Indexers

    • Like properties

    • Used when it is natural to access data by indexes - array notation - instead of simple names

    • Used as surface notation for associative arrays

  • Methods

    • For all other operations that encapsulate calculations on the data of the class


Collected references
Contents Index
C# operator table Earlier in these notes
Dictionaries in C# Later in these notes
Class methods Earlier in these notes
Instance methods Earlier in these notes
Indexers Earlier in these notes
Properties Earlier in these notes
Introduction to Methods in C#.
Our earlier encounter of integer sequences Earlier in these notes
Class Point and a client Earlier in these notes

 

Chapter 5: Data Access, Properties, and Methods
Course home     Author home     About producing this web     Previous lecture (top)     Next lecture (top)     Previous lecture (bund)     Next lecture (bund)     
Generated: February 7, 2011, 12:14:55