The C# Complete Reference code

 

listing 1
// A XML documentation example.
 
using System;
 
/** <remark>
 This is an example of multiline XML documentation.
 The Test class demonstrates several tags.
</remark>
*/
 
class Test {
  /// <summary>
  /// Main is where execution begins.
  /// </summary>
  public static void Main() {
    int sum;
  
    sum = Summation(5);
 Console.WriteLine("Summation of " + 5 + " is " + sum);
  }
 
  /// <summary>
  /// Summation returns the summation of its argument.
  /// <param name = "val">
  /// The value to be summed is passed in val.
  /// </param>
  /// <see cref="int"> </see>
  /// <returns>
  /// The summation is returned as an int value.
  /// </returns>
  /// </summary>
  static int Summation(int val) {
    int result = 0;
 
    for(int i=1; i <= val; i++)
      result += i;
 
    return result;
  }
}

listing 1
/* 
   This is a simple C# program.
 
   Call this program Example.cs.
*/
 
using System;
 
class Example {
  // A C# program begins with a call to Main().
  public static void Main() {
    Console.WriteLine("A simple C# program.");
  }
}

listing 2
// This version does not include the using System statement.
 
class Example {
 
  // A C# program begins with a call to Main().
  public static void Main() {
 
    // Here, Console.WriteLine is fully qualified.
    System.Console.WriteLine("A simple C# program.");
  }
}

listing 3
// This program demonstrates variables. 
 
using System;
 
class Example2 {  
  public static void Main() {  
    int x; // this declares a variable 
    int y; // this declares another variable 
 
    x = 100; // this assigns 100 to x
 
    Console.WriteLine("x contains " + x);  
 
    y = x / 2; 
 
    Console.Write("y contains x / 2: "); 
    Console.WriteLine(y); 
  }  
}

listing 4
/* 
   This program illustrates the differences
   between int and double.
*/ 
 
using System;
 
class Example3 { 
  public static void Main() { 
    int ivar;     // this declares an int variable
    double dvar;  // this declares a floating-point variable
 
    ivar = 100;   // assign ivar the value 100
   
    dvar = 100.0; // assign dvar the value 100.0
 
    Console.WriteLine("Original value of ivar: " + ivar);
    Console.WriteLine("Original value of dvar: " + dvar);
 
    Console.WriteLine(); // print a blank line
 
    // now, divide both by 3
    ivar = ivar / 3; 
    dvar = dvar / 3.0;
 
    Console.WriteLine("ivar after division: " + ivar);
    Console.WriteLine("dvar after division: " + dvar);
  } 
}

listing 5
// Compute the area of a circle.
 
using System; 
  
class Circle {  
  public static void Main() {  
    double radius;
    double area;
 
    radius = 10.0;
    area = radius * radius * 3.1416;
 
    Console.WriteLine("Area is " + area);
  }  
}

listing 6
// Demonstrate the if. 
 
using System;
 
class IfDemo { 
  public static void Main() { 
    int a, b, c; 
 
    a = 2; 
    b = 3; 
 
    if(a < b) Console.WriteLine("a is less than b");
 
    // this won't display anything 
    if(a == b) Console.WriteLine("you won't see this"); 
 
    Console.WriteLine();
 
    c = a - b; // c contains -1
 
    Console.WriteLine("c contains -1");
    if(c >= 0) Console.WriteLine("c is non-negative");
    if(c < 0) Console.WriteLine("c is negative");
 
    Console.WriteLine();
 
    c = b - a; // c now contains 1
    Console.WriteLine("c contains 1");
    if(c >= 0) Console.WriteLine("c is non-negative");
    if(c < 0) Console.WriteLine("c is negative");
  } 
}

listing 7
// Demonstrate the for loop.
 
using System;
 
class ForDemo {
  public static void Main() {
    int count;
 
    for(count = 0; count < 5; count = count+1)
      Console.WriteLine("This is count: " + count);
 
    Console.WriteLine("Done!");
  }
}

listing 8
// Demonstrate a block of code.
 
using System;
 
class BlockDemo {
  public static void Main() {
    int i, j, d;
 
    i = 5;
    j = 10;
 
    // the target of this if is a block
    if(i != 0) {
      Console.WriteLine("i does not equal zero");
      d = j / i;
      Console.WriteLine("j / i is " + d);
    }
  }
}

listing 9
// Compute the sum and product of the numbers from 1 to 10.
 
using System; 
  
class ProdSum {  
  public static void Main() {  
    int prod;
    int sum;
    int i;
 
    sum = 0;
    prod = 1;
 
    for(i=1; i <= 10; i++) {
      sum = sum + i;
      prod = prod * i;      
    }
    Console.WriteLine("Sum is " + sum);
    Console.WriteLine("Product is " + prod);
 
  }  
}

listing 10
// Demonstrate an @ identifier.
 
using System; 
  
class IdTest {  
  public static void Main() {  
    int @if; // use if as an identifier
 
    for(@if = 0; @if < 10; @if++)
      Console.WriteLine("@if is " + @if);
  }  
}

listing 1
// Compute the distance from the Earth to the sun, in inches.
 
using System;
 
class Inches {   
  public static void Main() {   
    long inches;
    long miles;
  
    miles = 93000000; // 93,000,000 miles to the sun
 
    // 5,280 feet in a mile, 12 inches in a foot
    inches = miles * 5280 * 12;
  
    Console.WriteLine("Distance to the sun: " +
                      inches + " inches.");
  
  }   
}

listing 2
// Use byte.
 
using System;
 
class Use_byte {   
  public static void Main() {   
    byte x;
    int sum;
 
    sum = 0;
    for(x = 1; x <= 100; x++)
      sum = sum + x;
 
    Console.WriteLine("Summation of 100 is " + sum);
  }   
}

listing 3
// Find the radius of a circle given its area.
 
using System;
 
class FindRadius {   
  public static void Main() {   
    Double r;
    Double area;
 
    area = 10.0;
 
    r = Math.Sqrt(area / 3.1416);
 
    Console.WriteLine("Radius is " + r);
  }   
}

listing 4
//  Demonstrate Math.Sin(), Math.Cos(), and Math.Tan().
 
using System;
 
class Trigonometry {   
  public static void Main() {   
    Double theta; // angle in radians
    
    for(theta = 0.1; theta <= 1.0; theta = theta + 0.1) {
      Console.WriteLine("Sine of " + theta + "  is " +
                        Math.Sin(theta));
      Console.WriteLine("Cosine of " + theta + "  is " +
                        Math.Cos(theta));
      Console.WriteLine("Tangent of " + theta + "  is " +
                        Math.Tan(theta));
      Console.WriteLine();
    }
 
  }   
}

listing 5
// Use the decimal type to compute a discount.
 
using System; 
 
class UseDecimal {    
  public static void Main() {    
    decimal price; 
    decimal discount;
    decimal discounted_price; 
 
    // compute discounted price
    price = 19.95m; 
    discount = 0.15m; // discount rate is 15%
 
    discounted_price = price - ( price * discount); 
 
    Console.WriteLine("Discounted price: $" + discounted_price); 
  }
}

listing 6
/*  
   Use the decimal type to compute the future value
   of an investment.
*/  
  
using System;
  
class FutVal {
  public static void Main() {
    decimal amount;  
    decimal rate_of_return; 
    int years, i;  
  
    amount = 1000.0M;
    rate_of_return = 0.07M;
    years = 10;
 
    Console.WriteLine("Original investment: $" + amount);
    Console.WriteLine("Rate of return: " + rate_of_return);
    Console.WriteLine("Over " + years + " years");
 
    for(i = 0; i < years; i++)
      amount = amount + (amount * rate_of_return);
 
    Console.WriteLine("Future value is $" + amount); 
  }
}

listing 7
// Demonstrate bool values.
 
using System;
 
class BoolDemo {
  public static void Main() {
    bool b;
 
    b = false;
    Console.WriteLine("b is " + b);
    b = true;
    Console.WriteLine("b is " + b);
 
    // a bool value can control the if statement
    if(b) Console.WriteLine("This is executed.");
 
    b = false;
    if(b) Console.WriteLine("This is not executed.");
 
    // outcome of a relational operator is a bool value
    Console.WriteLine("10 > 9 is " + (10 > 9));
  }
}

listing 8
// Use format commands. 
 
using System;
 
class DisplayOptions {   
  public static void Main() {   
    int i;
 
    Console.WriteLine("Value\tSquared\tCubed");
 
    for(i = 1; i < 10; i++)
      Console.WriteLine("{0}\t{1}\t{2}", 
                        i, i*i, i*i*i);
  }   
}

listing 9
/* 
   Use the C format specifier to output dollars and cents. 
*/ 
 
using System; 
 
class UseDecimal {    
  public static void Main() {    
    decimal price; 
    decimal discount;
    decimal discounted_price; 
 
    // compute discounted price
    price = 19.95m; 
    discount = 0.15m; // discount rate is 15%
 
    discounted_price = price - ( price * discount); 
 
    Console.WriteLine("Discounted price: {0:C}", discounted_price); 
  }    
}

listing 10
// Demonstrate escape sequences in strings.
 
using System;
 
class StrDemo {   
  public static void Main() {   
    Console.WriteLine("Line One\nLine Two\nLine Three");
    Console.WriteLine("One\tTwo\tThree");
    Console.WriteLine("Four\tFive\tSix");
 
    // embed quotes
    Console.WriteLine("\"Why?\", he asked.");
  }   
}

listing 11
// Demonstrate verbatim literal strings.
 
using System;
 
class Verbatim {   
  public static void Main() {   
    Console.WriteLine(@"This is a verbatim
string literal
that spans several lines.
");
    Console.WriteLine(@"Here is some tabbed output:
1 2 3 4
5 6 7 8
");
    Console.WriteLine(@"Programmers say, ""I like C#.""");
  }   
}

listing 12
// Demonstrate dynamic initialization. 
 
using System; 
 
class DynInit { 
  public static void Main() { 
    double s1 = 4.0, s2 = 5.0; // length of sides
 
    // dynamically initialize hypot 
    double hypot = Math.Sqrt( (s1 * s1) + (s2 * s2) );
 
    Console.Write("Hypotenuse of triangle with sides " +
                  s1 + " by " + s2 + " is ");
 
    Console.WriteLine("{0:#.###}.", hypot);
 
  } 
}

listing 13
// Demonstrate block scope.
 
using System;
 
class ScopeDemo {
  public static void Main() {
    int x; // known to all code within Main()
 
    x = 10;
    if(x == 10) { // start new scope
      int y = 20; // known only to this block
 
      // x and y both known here.
      Console.WriteLine("x and y: " + x + " " + y);
      x = y * 2;
    }
    // y = 100; // Error! y not known here 
 
    // x is still known here.
    Console.WriteLine("x is " + x);
  }
}

listing 14
// Demonstrate lifetime of a variable.
 
using System;
 
class VarInitDemo {
  public static void Main() {
    int x; 
 
    for(x = 0; x < 3; x++) {
      int y = -1; // y is initialized each time block is entered
      Console.WriteLine("y is: " + y); // this always prints -1
      y = 100; 
      Console.WriteLine("y is now: " + y);
    }
  }
}

listing 15
/* 
   This program attempts to declare a variable
   in an inner scope with the same name as one
   defined in an outer scope.
 
   *** This program will not compile. ***
*/ 
 
using System;
 
class NestVar { 
  public static void Main() { 
    int count; 
 
    for(count = 0; count < 10; count = count+1) {
      Console.WriteLine("This is count: " + count); 
    
      int count; // illegal!!!
      for(count = 0; count < 2; count++)
        Console.WriteLine("This program is in error!");
    }
  } 
}

listing 16
// Demonstrate automatic conversion from long to double.
 
using System;
 
class LtoD {   
  public static void Main() {   
    long L;
    double D;
  
    L = 100123285L;
    D = L;
  
    Console.WriteLine("L and D: " + L + " " + D);
  }   
}

listing 17
// *** This program will not compile. ***
 
using System;
 
class LtoD {   
  public static void Main() {   
    long L;
    double D;
  
    D = 100123285.0;
    L = D; // Illegal!!!
  
    Console.WriteLine("L and D: " + L + " " + D);
  
  }   
}

listing 18
// Demonstrate casting.
 
using System;
 
class CastDemo {   
  public static void Main() {   
    double x, y;
    byte b;
    int i;
    char ch;
    uint u;
    short s;
    long l;
 
    x = 10.0;
    y = 3.0;
 
    // cast an int into a double
    i = (int) (x / y); // cast double to int, fractional component lost
    Console.WriteLine("Integer outcome of x / y: " + i);
    Console.WriteLine();
    
    // cast an int into a byte, no data lost
    i = 255;
    b = (byte) i; 
    Console.WriteLine("b after assigning 255: " + b +
                      " -- no data lost.");
 
    // cast an int into a byte, data lost
    i = 257;
    b = (byte) i; 
    Console.WriteLine("b after assigning 257: " + b +
                      " -- data lost.");
    Console.WriteLine();
 
    // cast a uint into a short, no data lost
    u = 32000;
    s = (short) u;
    Console.WriteLine("s after assigning 32000: " + s +
                      " -- no data lost."); 
 
    // cast a uint into a short, data lost
    u = 64000;
    s = (short) u;
    Console.WriteLine("s after assigning 64000: " + s +
                      " -- data lost."); 
    Console.WriteLine();
 
    // cast a long into a uint, no data lost
    l = 64000;
    u = (uint) l;
    Console.WriteLine("u after assigning 64000: " + u +
                      " -- no data lost."); 
 
    // cast a long into a uint, data lost
    l = -12;
    u = (uint) l;
    Console.WriteLine("u after assigning -12: " + u +
                      " -- data lost."); 
    Console.WriteLine();
 
    // cast an int into a char
    b = 88; // ASCII code for X
    ch = (char) b;
    Console.WriteLine("ch after assigning 88: " + ch); 
  }   
}

listing 19
// A promotion surprise! 
 
using System; 
 
class PromDemo {    
  public static void Main() {    
    byte b; 
   
    b = 10; 
    b = (byte) (b * b); // cast needed!! 
 
    Console.WriteLine("b: "+ b); 
  }    
}

listing 20
// Using casts in an expression. 
 
using System; 
 
class CastExpr {    
  public static void Main() {    
    double n; 
 
     for(n = 1.0; n <= 10; n++) { 
       Console.WriteLine("The square root of {0} is {1}", 
                         n, Math.Sqrt(n)); 
 
       Console.WriteLine("Whole number part: {0}" ,  
                         (int) Math.Sqrt(n)); 
  
       Console.WriteLine("Fractional part: {0}",  
                         Math.Sqrt(n) - (int) Math.Sqrt(n) ); 
       Console.WriteLine();
    } 
 
  }    
}

listing 1
// Demonstrate the % operator.
 
using System;
 
class ModDemo {   
  public static void Main() {   
    int iresult, irem;
    double dresult, drem;
 
    iresult = 10 / 3;
    irem = 10 % 3;
 
    dresult = 10.0 / 3.0;
    drem = 10.0 % 3.0; 
 
    Console.WriteLine("Result and remainder of 10 / 3: " +
                       iresult + " " + irem);
    Console.WriteLine("Result and remainder of 10.0 / 3.0: " +
                       dresult + " " + drem);
  }   
}

listing 2
/*
   Demonstrate the difference between prefix
   postfix forms of ++.
*/
using System;
 
class PrePostDemo { 
  public static void Main() {   
    int x, y;
    int i;
 
    x = 1;
    Console.WriteLine("Series generated using y = x + x++;");
    for(i = 0; i < 10; i++) {
 
      y = x + x++; // postfix ++
 
      Console.WriteLine(y + " ");
    }
    Console.WriteLine();
 
    x = 1;
    Console.WriteLine("Series generated using y = x + ++x;");
    for(i = 0; i < 10; i++) {
 
      y = x + ++x; // prefix ++
 
      Console.WriteLine(y + " ");
    }
    Console.WriteLine();
   
  }
}

listing 3
// Demonstrate the relational and logical operators.
 
using System;
 
class RelLogOps {   
  public static void Main() {   
    int i, j;
    bool b1, b2;
 
    i = 10;
    j = 11;
    if(i < j) Console.WriteLine("i < j");
    if(i <= j) Console.WriteLine("i <= j");
    if(i != j) Console.WriteLine("i != j");
    if(i == j) Console.WriteLine("this won't execute");
    if(i >= j) Console.WriteLine("this won't execute");
    if(i > j) Console.WriteLine("this won't execute");
 
    b1 = true;
    b2 = false;
    if(b1 & b2) Console.WriteLine("this won't execute");
    if(!(b1 & b2)) Console.WriteLine("!(b1 & b2) is true");
    if(b1 | b2) Console.WriteLine("b1 | b2 is true");
    if(b1 ^ b2) Console.WriteLine("b1 ^ b2 is true");
  }   
}

listing 4
// Create an implication operator in C#.
 
using System;
 
class Implication { 
  public static void Main() {   
    bool p=false, q=false;
    int i, j;
 
    for(i = 0; i < 2; i++) {
      for(j = 0; j < 2; j++) {
        if(i==0) p = true;
        if(i==1) p = false;
        if(j==0) q = true;
        if(j==1) q = false;
        
        Console.WriteLine("p is " + p + ", q is " + q);
        if(!p | q) Console.WriteLine(p + " implies " + q +
                    " is " + true);  
        Console.WriteLine();
      }
    }
  }
}

listing 5
// Demonstrate the short-circuit operators.
 
using System;
 
class SCops {   
  public static void Main() {   
    int n, d;
 
    n = 10;
    d = 2;
    if(d != 0 && (n % d) == 0)
      Console.WriteLine(d + " is a factor of " + n);
 
    d = 0; // now, set d to zero
 
    // Since d is zero, the second operand is not evaluated.
    if(d != 0 && (n % d) == 0)
      Console.WriteLine(d + " is a factor of " + n); 
    
    /* Now, try the same thing without short-circuit operator.
       This will cause a divide-by-zero error.  */
    if(d != 0 & (n % d) == 0)
      Console.WriteLine(d + " is a factor of " + n);
  }   
}

listing 6
// Side-effects can be important.
 
using System;
 
class SideEffects {   
  public static void Main() {   
    int i;
    bool someCondition = false;
 
    i = 0;
 
    /* Here, i is still incremented even though
       the if statement fails. */
    if(someCondition & (++i < 100))
       Console.WriteLine("this won't be displayed");
    Console.WriteLine("if statement executed: " + i); // displays 1
 
    /* In this case, i is not incremented because
       the short-circuit operator skips the increment. */
    if(someCondition && (++i < 100))
      Console.WriteLine("this won't be displayed");
    Console.WriteLine("if statement executed: " + i); // still 1 !!
  }   
}

listing 7
// Use bitwise AND to make a number even.
 
using System;
 
class MakeEven { 
  public static void Main() {
    ushort num; 
    ushort i;    
 
    for(i = 1; i <= 10; i++) {
      num = i;
 
      Console.WriteLine("num: " + num);
 
      num = (ushort) (num & 0xFFFE); // num & 1111 1110
 
      Console.WriteLine("num after turning off bit zero: "
                        +  num + "\n"); 
    }
  }
}

listing 8
//  Use bitwise AND to determine if a number is odd.
 
using System;
 
class IsOdd { 
  public static void Main() {
    ushort num; 
 
    num = 10;
 
    if((num & 1) == 1)
      Console.WriteLine("This won't display.");
 
    num = 11;
 
    if((num & 1) == 1)
      Console.WriteLine(num + " is odd.");
 
  }
}

listing 9
// Display the bits within a byte. 
 
using System;
 
class ShowBits {
  public static void Main() {
    int t;
    byte val; 
 
    val = 123;
    for(t=128; t > 0; t = t/2) {
      if((val & t) != 0) Console.Write("1 "); 
      if((val & t) == 0) Console.Write("0 "); 
    }
  }
}

listing 10
//  Use bitwise OR to make a number odd.
 
using System;
 
class MakeOdd { 
  public static void Main() {
    ushort num; 
    ushort i;    
 
    for(i = 1; i <= 10; i++) {
      num = i;
 
      Console.WriteLine("num: " + num);
 
      num = (ushort) (num | 1); // num | 0000 0001
 
      Console.WriteLine("num after turning on bit zero: "
                        +  num + "\n"); 
    }
  }
}

listing 11
// Use XOR to encode and decode a message.
 
using System;
 
class Encode { 
  public static void Main() {
    char ch1 = 'H';
    char ch2 = 'i';
    char ch3 = '!';
    int key = 88;
 
    Console.WriteLine("Original message: " + ch1 + ch2 + ch3);
 
    // encode the message
    ch1 = (char) (ch1 ^ key);
    ch2 = (char) (ch2 ^ key);
    ch3 = (char) (ch3 ^ key);
 
    Console.WriteLine("Encoded message: " + ch1 + ch2 + ch3);
 
    // decode the message
    ch1 = (char) (ch1 ^ key);
    ch2 = (char) (ch2 ^ key);
    ch3 = (char) (ch3 ^ key);
   
    Console.WriteLine("Encoded message: " + ch1 + ch2 + ch3);
  }
}

listing 12
// Demonstrate the bitwise NOT.
 
using System;
 
class NotDemo {
  public static void Main() {
    sbyte b = -34;
 
    for(int t=128; t > 0; t = t/2) {
      if((b & t) != 0) Console.Write("1 "); 
      if((b & t) == 0) Console.Write("0 "); 
    }
    Console.WriteLine();
 
    // reverse all bits
    b = (sbyte) ~b;
 
    for(int t=128; t > 0; t = t/2) {
      if((b & t) != 0) Console.Write("1 "); 
      if((b & t) == 0) Console.Write("0 "); 
    }
  }
}

listing 13
// Demonstrate the shift << and >> operators.
 
using System;
 
class ShiftDemo {
  public static void Main() {
    int val = 1;
 
    for(int i = 0; i < 8; i++) { 
      for(int t=128; t > 0; t = t/2) {
        if((val & t) != 0) Console.Write("1 "); 
        if((val & t) == 0) Console.Write("0 "); 
      }
      Console.WriteLine();
      val = val << 1; // left shift
    }
    Console.WriteLine();
 
    val = 128;
    for(int i = 0; i < 8; i++) { 
      for(int t=128; t > 0; t = t/2) {
        if((val & t) != 0) Console.Write("1 "); 
        if((val & t) == 0) Console.Write("0 "); 
      }
      Console.WriteLine();
      val = val >> 1; // right shift
    }
  }
}

listing 14
// Use the shift operators to multiply and divide by 2.
 
using System;
 
class MultDiv { 
  public static void Main() {
    int n;
 
    n = 10;
 
    Console.WriteLine("Value of n: " + n);
 
    // multiply by 2
    n = n << 1;
    Console.WriteLine("Value of n after n = n * 2: " + n);
 
    // multiply by 4
    n = n << 2;
    Console.WriteLine("Value of n after n = n * 4: " + n);
 
    // divide by 2
    n = n >> 1;
    Console.WriteLine("Value of n after n = n / 2: " + n);
 
    // divide by 4
    n = n >> 2;
    Console.WriteLine("Value of n after n = n / 4: " + n);
    Console.WriteLine();
 
    // reset n
    n = 10;
    Console.WriteLine("Value of n: " + n);
 
    // multiply by 2, 30 times
    n = n << 30; // data is lost
    Console.WriteLine("Value of n after left-shifting 30 places: " + n);
 
  }
}

listing 15
// Prevent a division by zero using the ?.
 
using System;
 
class NoZeroDiv {
  public static void Main() {
    int result;
 
    for(int i = -5; i < 6; i++) {
      result = i != 0 ? 100 / i : 0;
      if(i != 0) 
        Console.WriteLine("100 / " + i + " is " + result);
    }
  }
}

listing 16
// Prevent a division by zero using the ?.
 
using System;
 
class NoZeroDiv2 {
  public static void Main() {
 
    for(int i = -5; i < 6; i++) 
      if(i != 0 ? true : false) 
        Console.WriteLine("100 / " + i +
                           " is " + 100 / i);
  }
}

listing 1
// Determine if a value is positive or negative.
 
using System;
 
class PosNeg { 
  public static void Main() {
    int i;
 
    for(i=-5; i <= 5; i++) {
      Console.Write("Testing " + i + ": ");
 
      if(i < 0) Console.WriteLine("negative");
      else Console.WriteLine("positive");
    }
  }
}

listing 2
// Determine if a value is positive, negative, or zero.
 
using System;
 
class PosNegZero { 
  public static void Main() {
    int i;
 
    for(i=-5; i <= 5; i++) {
 
      Console.Write("Testing " + i + ": ");
 
      if(i < 0) Console.WriteLine("negative");
      else if(i == 0) Console.WriteLine("no sign");
        else Console.WriteLine("positive");
    }
  }
}

listing 3
// Determine smallest single-digit factor.
 
using System;
 
class Ladder {   
  public static void Main() {   
    int num;
 
    for(num = 2; num < 12; num++) {
      if((num % 2) == 0)
        Console.WriteLine("Smallest factor of " + num + " is 2."); 
      else if((num % 3) == 0) 
        Console.WriteLine("Smallest factor of " + num + " is 3."); 
      else if((num % 5) == 0)
        Console.WriteLine("Smallest factor of " + num + " is 5."); 
      else if((num % 7) == 0) 
        Console.WriteLine("Smallest factor of " + num + " is 7."); 
      else 
        Console.WriteLine(num + " is not divisible by 2, 3, 5, or 7."); 
    }
  }
}

listing 4
// Demonstrate the switch.
 
using System;
 
class SwitchDemo {  
  public static void Main() {
    int i;
 
    for(i=0; i<10; i++)
      switch(i) {
        case 0: 
          Console.WriteLine("i is zero");
          break;
        case 1: 
          Console.WriteLine("i is one");
          break;
        case 2: 
          Console.WriteLine("i is two");
          break;
        case 3: 
          Console.WriteLine("i is three");
          break;
        case 4: 
          Console.WriteLine("i is four");
          break;
        default: 
          Console.WriteLine("i is five or more");
          break;
      }
  }  
}

listing 5
// Use a char to control the switch.
 
using System;
 
class SwitchDemo2 {  
  public static void Main() {
    char ch;
 
    for(ch='A'; ch<= 'E'; ch++)
      switch(ch) {
        case 'A': 
          Console.WriteLine("ch is A");
          break;
        case 'B': 
          Console.WriteLine("ch is B");
          break;
        case 'C': 
          Console.WriteLine("ch is C");
          break;
        case 'D': 
          Console.WriteLine("ch is D");
          break;
        case 'E': 
          Console.WriteLine("ch is E");
          break;
      }    
  }
}

listing 6
// Empty cases can fall through.
 
using System;
 
class EmptyCasesCanFall {  
  public static void Main() {
    int i;
 
    for(i=1; i < 5; i++) 
      switch(i) {
        case 1:
        case 2:
        case 3: Console.WriteLine("i is 1, 2 or 3");
          break;
        case 4: Console.WriteLine("i is 4");
          break;
      }
 
  }
}

listing 7
// A negatively running for loop.
 
using System;
 
class DecrFor {    
  public static void Main() {    
    int x;
 
    for(x = 100; x > -100; x -= 5)
      Console.WriteLine(x);
  }
}

listing 8
/*
   Determine if a number is prime.  If it is not,
   then display its largest factor.
*/
 
using System;
 
class FindPrimes {   
  public static void Main() {   
    int num;
    int i;
    int factor;
    bool isprime;
 
 
    for(num = 2; num < 20; num++) {
      isprime = true; 
      factor = 0;
 
      // see if num is evenly divisible
      for(i=2; i <= num/2; i++) {
        if((num % i) == 0) {
          // num is evenly divisible -- not prime
          isprime = false;
          factor = i;
        }
      }
 
      if(isprime)
        Console.WriteLine(num + " is prime.");
      else
        Console.WriteLine("Largest factor of " + num +
                          " is " + factor);
    }
 
  }   
}

listing 9
// Use commas in a for statement.
 
using System;
 
class Comma {   
  public static void Main() {   
    int i, j;
 
    for(i=0, j=10; i < j; i++, j--)
      Console.WriteLine("i and j: " + i + " " + j);
  }
}

listing 10
/*
   Use commas in a for statement to find
   the largest and smallest factor of a number.
*/
 
using System;
 
class Comma {   
  public static void Main() {   
    int i, j;
    int smallest, largest;
    int num;
 
    num = 100;
   
    smallest = largest = 1;
 
    for(i=2, j=num/2; (i <= num/2) & (j >= 2); i++, j--) {
 
      if((smallest == 1) & ((num % i) == 0)) 
        smallest = i;
 
      if((largest == 1) & ((num % j) == 0)) 
        largest = j;
 
    }
 
    Console.WriteLine("Largest factor: " + largest);
    Console.WriteLine("Smallest factor: " + smallest);
  }
}

listing 11
// Loop condition can be any bool expression.
 
using System;
 
class forDemo {   
  public static void Main() {   
    int i, j;
    bool done = false;
 
    for(i=0, j=100; !done; i++, j--) {
 
      if(i*i >= j) done = true;
 
      Console.WriteLine("i, j: " + i + " " + j);
    }
 
  }
}

listing 12
// Parts of the for can be empty.
 
using System;
 
class Empty {  
  public static void Main() {
    int i;
 
    for(i = 0; i < 10; ) {
      Console.WriteLine("Pass #" + i);
      i++; // increment loop control var
    }
 
  }  
}

listing 13
// Move more out of the for loop.
 
using System;
 
class Empty2 {  
  public static void Main() {
    int i;
 
    i = 0; // move initialization out of loop
    for(; i < 10; ) {
      Console.WriteLine("Pass #" + i);
      i++; // increment loop control var
    }
 
  }  
}

listing 14
// The body of a loop can be empty.
 
using System;
 
class Empty3 {  
  public static void Main() {
    int i;
    int sum = 0;
 
    // sum the numbers through 5 
    for(i = 1; i <= 5; sum += i++) ;
 
    Console.WriteLine("Sum is " + sum);
  }  
}

listing 15
// Declare loop control variable inside the for.
 
using System;
 
class ForVar {  
  public static void Main() {
    int sum = 0;
    int fact = 1;
 
    // Compute the factorial of the numbers through 5.
    for(int i = 1; i <= 5; i++) { 
      sum += i;  // i is known throughout the loop
      fact *= i;
    }
 
    // But, i is not known here.
 
    Console.WriteLine("Sum is " + sum);
    Console.WriteLine("Factorial is " + fact);
  }  
}

listing 16
// Compute the order of magnitude of an integer
 
using System;
 
class WhileDemo {  
  public static void Main() {
    int num;
    int mag;
 
    num = 435679;
    mag = 0;
 
    Console.WriteLine("Number: " + num);
 
    while(num > 0) {
      mag++;
      num = num / 10;
    };
 
    Console.WriteLine("Magnitude: " + mag);
  }  
}

listing 17
// Compute integer powers of 2.
 
using System;
 
class Power {  
  public static void Main() {
    int e;
    int result;
 
    for(int i=0; i < 10; i++) {
      result = 1;
      e = i;
 
      while(e > 0) {
        result *= 2;
        e--;
      }
 
      Console.WriteLine("2 to the " + i + 
                         " power is " + result);       
    }
  }  
}

listing 18
// Display the digits of an integer in reverse order.
 
using System;
 
class DoWhileDemo {  
  public static void Main() {
    int num;
    int nextdigit;
 
    num = 198;
 
    Console.WriteLine("Number: " + num);
 
    Console.Write("Number in reverse order: ");
 
    do {
      nextdigit = num % 10;
      Console.Write(nextdigit);
      num = num / 10;
    } while(num > 0);
 
    Console.WriteLine();
  }  
}

listing 19
// Using break to exit a loop.  
 
using System;
 
class BreakDemo { 
  public static void Main() { 
 
    // use break to exit this loop
    for(int i=-10; i <= 10; i++) { 
      if(i > 0) break; // terminate loop when i is positive
      Console.Write(i + " "); 
    } 
    Console.WriteLine("Done"); 
  } 
}

listing 20
// Using break to exit a do-while loop.  
 
using System;
 
class BreakDemo2 { 
  public static void Main() { 
    int i;
 
    i = -10;    
    do {
      if(i > 0) break;
      Console.Write(i + " ");
      i++;
    } while(i <= 10);
 
    Console.WriteLine("Done"); 
  } 
}

listing 21
// Find the smallest factor of a value.
 
using System;
 
class FindSmallestFactor { 
  public static void Main() { 
    int factor = 1;
    int num = 1000;
     
    for(int i=2; i < num/2; i++) { 
      if((num%i) == 0) {
        factor = i;
        break; // stop loop when factor is found
      }
    } 
    Console.WriteLine("Smallest factor is " + factor); 
  } 
}

listing 22
// Using break with nested loops. 
 
using System;
 
class BreakNested { 
  public static void Main() { 
 
    for(int i=0; i<3; i++) { 
      Console.WriteLine("Outer loop count: " + i); 
      Console.Write("    Inner loop count: ");
 
      int t = 0;            
      while(t < 100) { 
        if(t == 10) break; // terminate loop if t is 10 
        Console.Write(t + " "); 
        t++;
      } 
      Console.WriteLine(); 
    } 
    Console.WriteLine("Loops complete."); 
  } 
}

listing 23
// Use continue.
 
using System;
 
class ContDemo {  
  public static void Main() {
 
    // print even numbers between 0 and 100
    for(int i = 0; i <= 100; i++) { 
      if((i%2) != 0) continue; // iterate
      Console.WriteLine(i);
    }
 
  }  
}

listing 24
// Use goto with a switch.
 
using System;
 
class SwitchGoto {  
  public static void Main() {
 
    for(int i=1; i < 5; i++) {
      switch(i) {
        case 1:
          Console.WriteLine("In case 1");
          goto case 3;
        case 2:
          Console.WriteLine("In case 2");
          goto case 1;
        case 3:
          Console.WriteLine("In case 3");
          goto default;
        default:
          Console.WriteLine("In default");
          break;
      }
 
      Console.WriteLine();
    }
 
//    goto case 1; // Error! Can't jump into a switch.
  }
}

listing 25
// Demonstrate the goto.
 
using System; 
 
class Use_goto {    
  public static void Main() {    
    int i=0, j=0, k=0;
 
    for(i=0; i < 10; i++) {
      for(j=0; j < 10; j++ ) {
        for(k=0; k < 10; k++) {
          Console.WriteLine("i, j, k: " + i + " " + j + " " + k);
          if(k == 3) goto stop;
        }
      }
    }
 
stop:
    Console.WriteLine("Stopped! i, j, k: " + i + ", " + j + " " + k);
   
  } 
}

listing 1
// A program that uses the Building class.  
 
using System; 
 
class Building {  
  public int floors;    // number of floors
  public int area;      // total square footage of building
  public int occupants; // number of occupants
}  
  
// This class declares an object of type Building.  
class BuildingDemo {  
  public static void Main() {  
    Building house = new Building(); // create a Building object
    int areaPP; // area per person
  
    // assign values to fields in house
    house.occupants = 4; 
    house.area = 2500; 
    house.floors = 2; 
  
    // compute the area per person
    areaPP = house.area / house.occupants; 
  
    Console.WriteLine("house has:\n  " +
                      house.floors + " floors\n  " +
                      house.occupants + " occupants\n  " +
                      house.area + " total area\n  " +
                      areaPP + " area per person");
  }  
}

listing 2
// This program creates two Building objects.
 
using System; 
 
class Building {  
  public int floors;    // number of floors
  public int area;      // total square footage of building
  public int occupants; // number of occupants
}  
  
// This class declares two objects of type Building.  
class BuildingDemo {  
  public static void Main() {  
    Building house = new Building();  
    Building office = new Building();
 
    int areaPP; // area per person
  
    // assign values to fields in house
    house.occupants = 4; 
    house.area = 2500; 
    house.floors = 2; 
 
    // assign values to fields in office
    office.occupants = 25; 
    office.area = 4200; 
    office.floors = 3; 
  
    // compute the area per person in house
    areaPP = house.area / house.occupants; 
  
    Console.WriteLine("house has:\n  " +
                      house.floors + " floors\n  " +
                      house.occupants + " occupants\n  " +
                      house.area + " total area\n  " +
                      areaPP + " area per person");
 
    Console.WriteLine();
 
    // compute the area per person in office
    areaPP = office.area / office.occupants; 
 
    Console.WriteLine("office has:\n  " +
                      office.floors + " floors\n  " +
                      office.occupants + " occupants\n  " +
                      office.area + " total area\n  " +
                      areaPP + " area per person");
  }  
}

listing 3
// Add a method to Building.
 
using System; 
 
class Building {  
  public int floors;    // number of floors
  public int area;      // total square footage of building
  public int occupants; // number of occupants
 
  // Display the area per person. 
  public void areaPerPerson() { 
    Console.WriteLine("  " + area / occupants +
                      " area per person");
  } 
}  
 
// Use the areaPerPerson() method.
class BuildingDemo {  
  public static void Main() {  
    Building house = new Building();  
    Building office = new Building();
 
 
    // assign values to fields in house
    house.occupants = 4; 
    house.area = 2500; 
    house.floors = 2; 
 
    // assign values to fields in office
    office.occupants = 25; 
    office.area = 4200; 
    office.floors = 3; 
  
 
    Console.WriteLine("house has:\n  " +
                      house.floors + " floors\n  " +
                      house.occupants + " occupants\n  " +
                      house.area + " total area");
    house.areaPerPerson();
 
    Console.WriteLine();
 
    Console.WriteLine("office has:\n  " +
                      office.floors + " floors\n  " +
                      office.occupants + " occupants\n  " +
                      office.area + " total area");
    office.areaPerPerson();
  }  
}

listing 4
// Return a value from areaPerPerson().
 
using System; 
 
class Building {  
  public int floors;    // number of floors
  public int area;      // total square footage of building
  public int occupants; // number of occupants
 
  // Return the area per person. 
  public int areaPerPerson() { 
    return area / occupants;
  } 
}  
  
// Use the return value from areaPerPerson().  
class BuildingDemo {  
  public static void Main() {  
    Building house = new Building();  
    Building office = new Building();
    int areaPP; // area per person
 
    // assign values to fields in house
    house.occupants = 4; 
    house.area = 2500; 
    house.floors = 2; 
 
    // assign values to fields in office
    office.occupants = 25; 
    office.area = 4200; 
    office.floors = 3; 
  
    // obtain area per person for house
    areaPP = house.areaPerPerson();
 
    Console.WriteLine("house has:\n  " +
                      house.floors + " floors\n  " +
                      house.occupants + " occupants\n  " +
                      house.area + " total area\n  " +
                      areaPP + " area per person");
 
 
    Console.WriteLine();
 
    // obtain area per person for office
    areaPP = office.areaPerPerson();
 
    Console.WriteLine("office has:\n  " +
                      office.floors + " floors\n  " +
                      office.occupants + " occupants\n  " +
                      office.area + " total area\n  " +
                      areaPP + " area per person");
  }  
}

listing 5
// A simple example that uses a parameter.
 
using System;
 
class ChkNum { 
  // Return true if x is prime.
  public bool isPrime(int x) {
    for(int i=2; i <= x/i; i++)
      if((x %i) == 0) return false;
 
    return true;
  }

 
class ParmDemo { 
  public static void Main() { 
    ChkNum ob = new ChkNum();
 
    for(int i=1; i < 10; i++)
      if(ob.isPrime(i)) Console.WriteLine(i + " is prime.");
      else Console.WriteLine(i + " is not prime.");
 
  } 
}

listing 6
// Add a method that takes two arguments.
 
using System;
 
class ChkNum { 
  // Return true if x is prime.
  public bool isPrime(int x) {
    for(int i=2; i <= x/i; i++)
      if((x %i) == 0) return false;
 
    return true;
  }
 
  // Return the least common factor.
  public int leastComFactor(int a, int b) {
    int max;
 
    if(isPrime(a) | isPrime(b)) return 1;
 
    max = a < b ? a : b;
 
    for(int i=2; i <= max/2; i++)
      if(((a%i) == 0) & ((b%i) == 0)) return i;
 
    return 1;
  }

 
class ParmDemo { 
  public static void Main() { 
    ChkNum ob = new ChkNum();
    int a, b;
 
    for(int i=1; i < 10; i++)
      if(ob.isPrime(i)) Console.WriteLine(i + " is prime.");
      else Console.WriteLine(i + " is not prime.");
 
    a = 7;
    b = 8;
    Console.WriteLine("Least common factor for " +
                      a + " and " + b + " is " +
                      ob.leastComFactor(a, b));
 
    a = 100;
    b = 8;
    Console.WriteLine("Least common factor for " +
                      a + " and " + b + " is " +
                      ob.leastComFactor(a, b));
 
    a = 100;
    b = 75;
    Console.WriteLine("Least common factor for " +
                      a + " and " + b + " is " +
                      ob.leastComFactor(a, b));
 
  } 
}

listing 7
/*
   Add a parameterized method that computes the  
   maximum number of people that can occupy a
   building assuming each needs a specified
   minimum space.
*/
 
using System; 
 
class Building {  
  public int floors;    // number of floors
  public int area;      // total square footage of building
  public int occupants; // number of occupants
 
  // Return the area per person. 
  public int areaPerPerson() { 
    return area / occupants;
  } 
 
  /* Return the maximum number of occupants if each
     is to have at least the specified minimum area. */
  public int maxOccupant(int minArea) {
    return area / minArea;
  }
}  
 
// Use maxOccupant().
class BuildingDemo {  
  public static void Main() {  
    Building house = new Building();  
    Building office = new Building();
 
    // assign values to fields in house
    house.occupants = 4; 
    house.area = 2500; 
    house.floors = 2; 
 
    // assign values to fields in office
    office.occupants = 25; 
    office.area = 4200; 
    office.floors = 3; 
  
    Console.WriteLine("Maximum occupants for house if each has " +
                      300 + " square feet: " +
                      house.maxOccupant(300));
 
    Console.WriteLine("Maximum occupants for office if each has " +
                      300 + " square feet: " +
                      office.maxOccupant(300));
  }  
}

listing 8
public void m() {
  char a, b;
 
  // ...
 
  if(a==b) {
    Console.WriteLine("equal");
    return;
  } else {
    Console.WriteLine("not equal");
    return;
  }
  Console.WriteLine("this is unreachable");
}

listing 9
// A simple constructor.
 
using System;
 
class MyClass {
  public int x;
 
  public MyClass() {
    x = 10;
  }  
}  
  
class ConsDemo {  
  public static void Main() {  
    MyClass t1 = new MyClass();
    MyClass t2 = new MyClass();
 
    Console.WriteLine(t1.x + " " + t2.x);
  }  
}

listing 10
// A parameterized constructor.
 
using System;
 
class MyClass {
  public int x;
 
  public MyClass(int i) {
    x = i;
  }  
}  
  
class ParmConsDemo {  
  public static void Main() {  
    MyClass t1 = new MyClass(10);
    MyClass t2 = new MyClass(88);
 
    Console.WriteLine(t1.x + " " + t2.x);
  }  
}

listing 11
// Add a constructor to Building.
 
using System; 
 
class Building {  
  public int floors;    // number of floors
  public int area;      // total square footage of building
  public int occupants; // number of occupants
 
 
  public Building(int f, int a, int o) {
    floors = f;
    area = a;
    occupants = o;
  }
 
  // Display the area per person. 
  public int areaPerPerson() { 
    return area / occupants;
  } 
 
  /* Return the maximum number of occupants if each
     is to have at least the specified minimum area. */
  public int maxOccupant(int minArea) {
    return area / minArea;
  }
}  
  
// Use the parameterized Building constructor.
class BuildingDemo {  
  public static void Main() {  
    Building house = new Building(2, 2500, 4);  
    Building office = new Building(3, 4200, 25);
 
    Console.WriteLine("Maximum occupants for house if each has " +
                      300 + " square feet: " +
                      house.maxOccupant(300));
 
    Console.WriteLine("Maximum occupants for office if each has " +
                      300 + " square feet: " +
                      office.maxOccupant(300));
  }  
}

listing 12
// Use new with a value type.
 
using System;
 
class newValue { 
  public static void Main() { 
    int i = new int(); // initialize i to zero
 
    Console.WriteLine("The value of i is: " + i);
  } 
}

listing 13
// Demonstrate a destructor.
 
using System;
 
class Destruct { 
  public int x; 
 
  public Destruct(int i) { 
    x = i; 
  }   
 
  // called when object is recycled
  ~Destruct() {
    Console.WriteLine("Destructing " + x);
  }
  
  // generates an object that is immediately destroyed
  public void generator(int i) {
    Destruct o = new Destruct(i);
  }
 
}   
   
class DestructDemo {   
  public static void Main() {   
    int count;
 
    Destruct ob = new Destruct(0);
 
    /* Now, generate a large number of objects.  At
       some point, garbage collection will occur. 
       Note: you might need to increase the number
       of objects generated in order to force
       garbage collection. */
 
    for(count=1; count < 100000; count++)
      ob.generator(count); 
 
    Console.WriteLine("Done");
  }   
}

listing 14
using System;
 
class Rect {
  public int width;
  public int height;
 
  public Rect(int w, int h) {
    width = w;
    height = h;
  }
 
  public int area() {
    return width * height;
  }
}
 
class UseRect {
  public static void Main() {  
    Rect r1 = new Rect(4, 5);
    Rect r2 = new Rect(7, 9);
 
    Console.WriteLine("Area of r1: " + r1.area());
 
    Console.WriteLine("Area of r2: " + r2.area());
 
  }
}

listing 15
using System;
 
class Rect {
  public int width;
  public int height;
 
  public Rect(int w, int h) {
    this.width = w;
    this.height = h;
  }
 
  public int area() {
    return this.width * this.height;
  }
}
 
class UseRect {
  public static void Main() {  
    Rect r1 = new Rect(4, 5);
    Rect r2 = new Rect(7, 9);
 
    Console.WriteLine("Area of r1: " + r1.area());
 
    Console.WriteLine("Area of r2: " + r2.area());
 
  }
}

listing 1
// Demonstrate a one-dimensional array.
 
using System;
 
class ArrayDemo { 
  public static void Main() { 
    int[] sample = new int[10];
    int i; 
 
    for(i = 0; i < 10; i = i+1) 
      sample[i] = i;
 
    for(i = 0; i < 10; i = i+1) 
      Console.WriteLine("sample[" + i + "]: " +
                         sample[i]); 
  } 
}

listing 2
// Compute the average of a set of values.
 
using System;
 
class Average { 
  public static void Main() { 
    int[] nums = new int[10];
    int avg = 0;
 
    nums[0] = 99;
    nums[1] = 10;
    nums[2] = 100;
    nums[3] = 18;
    nums[4] = 78;
    nums[5] = 23;
    nums[6] = 63;
    nums[7] = 9;
    nums[8] = 87;
    nums[9] = 49;
 
    for(int i=0; i < 10; i++) 
      avg = avg + nums[i];
 
    avg = avg / 10;
 
    Console.WriteLine("Average: " + avg);
  } 
}

listing 3
// Compute the average of a set of values.
 
using System;
 
class Average { 
  public static void Main() { 
    int[] nums = { 99, 10, 100, 18, 78, 23,
                   63, 9, 87, 49 };
    int avg = 0;
 
    for(int i=0; i < 10; i++) 
      avg = avg + nums[i];
 
    avg = avg / 10;
 
    Console.WriteLine("Average: " + avg);
  } 
}

listing 4
// Demonstrate an array overrun.
 
using System;
 
class ArrayErr { 
  public static void Main() { 
    int[] sample = new int[10];
    int i; 
 
    // generate an array overrun
    for(i = 0; i < 100; i = i+1) 
      sample[i] = i;
  } 
}

listing 5
// Demonstrate a two-dimensional array. 
 
using System;
 
class TwoD { 
  public static void Main() { 
    int t, i;
    int[,] table = new int[3, 4]; 
 
    for(t=0; t < 3; ++t) { 
      for(i=0; i < 4; ++i) { 
        table[t,i] = (t*4)+i+1; 
        Console.Write(table[t,i] + " "); 
      } 
      Console.WriteLine();
    } 
  }
}

listing 6
// Sum the values on a diagonal of a 3x3x3 matrix.
 
using System;
 
class ThreeDMatrix { 
  public static void Main() { 
    int[,,] m = new int[3, 3, 3];
    int sum = 0;
    int n = 1;
 
    for(int x=0; x < 3; x++)
      for(int y=0; y < 3; y++)
        for(int z=0; z < 3; z++) 
          m[x, y, z] = n++;
 
 
    sum = m[0,0,0] + m[1,1,1] + m[2, 2, 2];
 
    Console.WriteLine("Sum of first diagonal: " + sum);
  } 
}

listing 7
// Initialize a two-dimensional array.
 
using System;
 
class Squares { 
  public static void Main() { 
    int[,] sqrs = {
      { 1, 1 },
      { 2, 4 },
      { 3, 9 },
      { 4, 16 },
      { 5, 25 },
      { 6, 36 },
      { 7, 49 },
      { 8, 64 },
      { 9, 81 },
      { 10, 100 }
    };
    int i, j;
 
    for(i=0; i < 10; i++) { 
      for(j=0; j < 2; j++) 
        Console.Write(sqrs[i,j] + " ");  
      Console.WriteLine(); 
    } 
  } 
}

listing 8
// Demonstrate jagged arrays.
 
using System;
 
class Jagged { 
  public static void Main() { 
    int[][] jagged = new int[3][]; 
    jagged[0] = new int[4]; 
    jagged[1] = new int[3]; 
    jagged[2] = new int[5]; 
 
    int i;
 
    // store values in first array
    for(i=0; i < 4; i++)  
      jagged[0][i] = i; 
 
    // store values in second array
    for(i=0; i < 3; i++)  
      jagged[1][i] = i; 
 
    // store values in third array
    for(i=0; i < 5; i++)  
      jagged[2][i] = i; 
 
 
    // display values in first array
    for(i=0; i < 4; i++)  
      Console.Write(jagged[0][i] + " "); 
 
    Console.WriteLine();
 
    // display values in second array
    for(i=0; i < 3; i++)  
      Console.Write(jagged[1][i] + " "); 
 
    Console.WriteLine();
 
    // display values in third array
    for(i=0; i < 5; i++)  
      Console.Write(jagged[2][i] + " "); 
 
    Console.WriteLine();
  } 
}

listing 9
// Assigning array reference variables.
 
using System;
 
class AssignARef { 
  public static void Main() { 
    int i;
 
    int[] nums1 = new int[10];
    int[] nums2 = new int[10];
 
    for(i=0; i < 10; i++) nums1[i] = i;
 
    for(i=0; i < 10; i++) nums2[i] = -i;
 
    Console.Write("Here is nums1: ");
    for(i=0; i < 10; i++)
      Console.Write(nums1[i] + " ");  
    Console.WriteLine();
 
    Console.Write("Here is nums2: ");
    for(i=0; i < 10; i++)
      Console.Write(nums2[i] + " ");  
    Console.WriteLine();
 
    nums2 = nums1; // now nums2 refers to nums1
 
    Console.Write("Here is nums2 after assignment: ");
    for(i=0; i < 10; i++)
      Console.Write(nums2[i] + " ");  
    Console.WriteLine();
 
   // now operate on nums1 array through nums2
   nums2[3] = 99;
 
    Console.Write("Here is nums1 after change through nums2: ");
    for(i=0; i < 10; i++)
      Console.Write(nums1[i] + " ");  
    Console.WriteLine();
  } 
}

listing 10
// Use the Length array property. 
 
using System;
 
class LengthDemo { 
  public static void Main() { 
    int[] nums = new int[10]; 
 
    Console.WriteLine("Length of nums is " + nums.Length); 
 
    // use Length to initialize nums
    for(int i=0; i < nums.Length; i++) 
      nums[i] = i * i; 
 
    // now use Length to display nums 
    Console.Write("Here is nums: ");
    for(int i=0; i < nums.Length; i++) 
      Console.Write(nums[i] + " "); 
 
    Console.WriteLine();
  } 
}

listing 11
// Use the Length array property on a 3-D array.
 
using System;
 
class LengthDemo3D { 
  public static void Main() { 
    int[,,] nums = new int[10, 5, 6]; 
 
    Console.WriteLine("Length of nums is " + nums.Length); 
 
  } 
}

listing 12
// Reverse an array.
 
using System;
 
class RevCopy { 
  public static void Main() { 
    int i,j;
    int[] nums1 = new int[10];
    int[] nums2 = new int[10];
 
    for(i=0; i < nums1.Length; i++) nums1[i] = i;
 
    Console.Write("Original contents: ");
    for(i=0; i < nums2.Length; i++)
      Console.Write(nums1[i] + " ");  
 
    Console.WriteLine();
 
    // reverse copy nums1 to nums2
    if(nums2.Length >= nums1.Length) // make sure nums2 is long enough
      for(i=0, j=nums1.Length-1; i < nums1.Length; i++, j--)
        nums2[j] = nums1[i];
 
    Console.Write("Reversed contents: ");
    for(i=0; i < nums2.Length; i++)
      Console.Write(nums2[i] + " ");  
 
    Console.WriteLine();
  }
}

listing 13
// Demonstrate Length with jagged arrays.
 
using System;
 
class Jagged { 
  public static void Main() { 
    int[][] network_nodes = new int[4][]; 
    network_nodes[0] = new int[3]; 
    network_nodes[1] = new int[7]; 
    network_nodes[2] = new int[2]; 
    network_nodes[3] = new int[5]; 
 
 
    int i, j;
 
    // fabricate some fake CPU usage data   
    for(i=0; i < network_nodes.Length; i++)  
      for(j=0; j < network_nodes[i].Length; j++) 
        network_nodes[i][j] = i * j + 70; 
 
 
    Console.WriteLine("Total number of network nodes: " +
                      network_nodes.Length + "\n");
 
    for(i=0; i < network_nodes.Length; i++) { 
      for(j=0; j < network_nodes[i].Length; j++) {
        Console.Write("CPU usage at node " + i + 
                      " CPU " + j + ": ");
        Console.Write(network_nodes[i][j] + "% "); 
        Console.WriteLine(); 
      }
      Console.WriteLine(); 
    }
 
  } 
}

listing 14
// Use the foreach loop.
 
using System;
 
class ForeachDemo {
  public static void Main() {
    int sum = 0;
    int[] nums = new int[10];
 
    // give nums some values
    for(int i = 0; i < 10; i++) 
      nums[i] = i;
 
    // use foreach to display and sum the values
    foreach(int x in nums) {
      Console.WriteLine("Value is: " + x);
      sum += x;
    }
    Console.WriteLine("Summation: " + sum);
  }
}

listing 15
// Use break with a foreach.
 
using System;
 
class ForeachDemo {
  public static void Main() {
    int sum = 0;
    int[] nums = new int[10];
 
    // give nums some values
    for(int i = 0; i < 10; i++) 
      nums[i] = i;
 
    // use foreach to display and sum the values
    foreach(int x in nums) {
      Console.WriteLine("Value is: " + x);
      sum += x;
      if(x == 4) break; // stop the loop when 4 is obtained
    }
    Console.WriteLine("Summation of first 5 elements: " + sum);
  }
}

listing 16
// Use foreach on a two-dimensional array.
 
using System;
 
class ForeachDemo2 {
  public static void Main() {
    int sum = 0;
    int[,] nums = new int[3,5];
 
    // give nums some values
    for(int i = 0; i < 3; i++) 
      for(int j=0; j < 5; j++)
        nums[i,j] = (i+1)*(j+1);
 
    // use foreach to display and sum the values
    foreach(int x in nums) {
      Console.WriteLine("Value is: " + x);
      sum += x;
    }
    Console.WriteLine("Summation: " + sum);
  }
}

listing 17
// Search an array using foreach.
 
using System;
 
class Search {
  public static void Main() {
    int[] nums = new int[10];
    int val;
    bool found = false;
 
    // give nums some values
    for(int i = 0; i < 10; i++) 
      nums[i] = i;
 
    val = 5;
 
    // use foreach to search nums for key
    foreach(int x in nums) {
      if(x == val) {
        found = true;
        break;
      }
    }
 
    if(found) 
      Console.WriteLine("Value found!");
  }
}

listing 18
// Introduce string.
 
using System;
 
class StringDemo { 
  public static void Main() { 
 
    char[] charray = {'A', ' ', 's', 't', 'r', 'i', 'n', 'g', '.' };
    string str1 = new string(charray);
    string str2 = "Another string.";
 
    Console.WriteLine(str1);
    Console.WriteLine(str2);
  } 
}

listing 19
// Some string operations. 
 
using System; 
 
class StrOps {  
  public static void Main() {  
    string str1 = 
      "When it comes to .NET programming, C# is #1.";  
    string str2 = string.Copy(str1); 
    string str3 = "C# strings are powerful.";  
    string strUp, strLow;
    int result, idx; 
 
    Console.WriteLine("str1: " + str1);
 
    Console.WriteLine("Length of str1: " +  
                       str1.Length);  
  
    // create upper- and lowercase versions of str1 
    strLow = str1.ToLower();
    strUp =  str1.ToUpper();
    Console.WriteLine("Lowercase version of str1:\n    " +
                      strLow);
    Console.WriteLine("Uppercase version of str1:\n    " +
                      strUp);
 
    Console.WriteLine();  
 
    // display str1, one char at a time. 
    Console.WriteLine("Display str1, one char at a time.");
    for(int i=0; i < str1.Length; i++) 
      Console.Write(str1[i]);  
    Console.WriteLine("\n");  
 
    // compare strings
    if(str1 == str2)  
      Console.WriteLine("str1 == str2");  
    else  
      Console.WriteLine("str1 != str2");  
  
    if(str1 == str3)  
      Console.WriteLine("str1 == str3");  
    else  
      Console.WriteLine("str1 != str3");  
 
    result = str1.CompareTo(str3); 
    if(result == 0) 
      Console.WriteLine("str1 and str3 are equal"); 
    else if(result < 0) 
      Console.WriteLine("str1 is less than str3"); 
    else 
      Console.WriteLine("str1 is greater than str3"); 
 
    Console.WriteLine();  
 
    // assign a new string to str2 
    str2 = "One Two Three One"; 
 
    // search string
    idx = str2.IndexOf("One"); 
    Console.WriteLine("Index of first occurrence of One: " + idx); 
    idx = str2.LastIndexOf("One"); 
    Console.WriteLine("Index of last occurrence of One: " + idx); 
     
  }  
}

listing 20
// Demonstrate string arrays. 
 
using System;
 
class StringArrays { 
  public static void Main() { 
    string[] str = { "This", "is", "a", "test." }; 
 
    Console.WriteLine("Original array: "); 
    for(int i=0; i < str.Length; i++)
      Console.Write(str[i] + " "); 
    Console.WriteLine("\n"); 
 
    // change a string 
    str[1] = "was"; 
    str[3] = "test, too!"; 
 
    Console.WriteLine("Modified array: ");
    for(int i=0; i < str.Length; i++)
      Console.Write(str[i] + " "); 
  } 
}

listing 21
// Display the digits of an integer using words.
 
using System;
 
class ConvertDigitsToWords {  
  public static void Main() {
    int num;
    int nextdigit;
    int numdigits;
    int[] n = new int[20];
    
    string[] digits = { "zero", "one", "two",
                        "three", "four", "five",
                        "six", "seven", "eight",
                        "nine" };
 
    num = 1908;
 
    Console.WriteLine("Number: " + num);
 
    Console.Write("Number in words: ");
    
    nextdigit = 0;
    numdigits = 0;
  
    /* Get individual digits and store in n.
       These digits are stored in reverse order. */
    do {
      nextdigit = num % 10;
      n[numdigits] = nextdigit;
      numdigits++;
      num = num / 10;
    } while(num > 0);
    numdigits--;
 
    // display words
    for( ; numdigits >= 0; numdigits--)
      Console.Write(digits[n[numdigits]] + " ");
 
    Console.WriteLine();
  }  
}

listing 22
// Use Substring().
 
using System;
 
class SubStr { 
  public static void Main() { 
    string orgstr = "C# makes strings easy.";
 
    // construct a substring
    string substr = orgstr.Substring(5, 12);
    
    Console.WriteLine("orgstr: " + orgstr);
    Console.WriteLine("substr: " + substr);
 
  } 
}

listing 23
// A string can control a switch statement.
 
using System;
 
class StringSwitch { 
  public static void Main() { 
    string[] strs = { "one", "two", "three", "two", "one" };
 
    foreach(string s in strs) {
      switch(s) {
        case "one":
          Console.Write(1);
          break;
        case "two":
          Console.Write(2);
          break;
        case "three":
          Console.Write(3);
          break;
      }
    }
    Console.WriteLine();
 
  }
}

listing 1
// Public vs private access.
 
using System;
 
class MyClass { 
  private int alpha; // private access explicitly specified
  int beta;          // private access by default
  public int gamma;  // public access
 
  /* Methods to access alpha and beta.  It is OK for a
     member of a class to access a private member
     of the same class.
  */
  public void setAlpha(int a) {
    alpha = a; 
  }
 
  public int getAlpha() {
    return alpha;
  }
 
  public void setBeta(int a) {
    beta = a; 
  }
 
  public int getBeta() {
    return beta;
  }

 
class AccessDemo { 
  public static void Main() { 
    MyClass ob = new MyClass(); 
 
    /* Access to alpha and beta is allowed only
       through methods. */
    ob.setAlpha(-99);
    ob.setBeta(19);
    Console.WriteLine("ob.alpha is " + ob.getAlpha());
    Console.WriteLine("ob.beta is " + ob.getBeta());
 
    // You cannot access alpha or beta like this:
//  ob.alpha = 10; // Wrong! alpha is private!
//  ob.beta = 9;   // Wrong! beta is private!
 
    // It is OK to directly access gamma because it is public.
    ob.gamma = 99; 
   } 
}

listing 2
// A stack class for characters.  
 
using System; 
 
class Stack {  
  // these members are private
  char[] stck; // holds the stack 
  int tos;     // index of the top of the stack 
  
  // Construct an empty Stack given its size. 
  public Stack(int size) {  
    stck = new char[size]; // allocate memory for stack  
    tos = 0;  
  }  
 
  // Push characters onto the stack. 
  public void push(char ch) {  
    if(tos==stck.Length) {  
      Console.WriteLine(" -- Stack is full.");  
      return;  
    }  
      
    stck[tos] = ch; 
    tos++; 
  }  
  
  // Pop a character from the stack. 
  public char pop() {  
    if(tos==0) {  
      Console.WriteLine(" -- Stack is empty.");  
      return (char) 0;   
    }  
    
    tos--;  
    return stck[tos];  
  }
 
  // Return true if the stack is full.
  public bool full() {
    return tos==stck.Length;   
  }
 
  // Return true if the stack is empty.
  public bool empty() {
    return tos==0;
  }
 
  // Return total capacity of the stack.
  public int capacity() {
    return stck.Length;
  }
 
  // Return number of objects currently on the stack.
  public int getNum() {
    return tos;
  }

listing 3
// Demonstrate the Stack class.  
 
using System;
 
class StackDemo {  
  public static void Main() {  
    Stack stk1 = new Stack(10);  
    Stack stk2 = new Stack(10);  
    Stack stk3 = new Stack(10);  
    char ch;  
    int i;  
  
    // Put some characters into stk1.
    Console.WriteLine("Push A through J onto stk1.");
    for(i=0; !stk1.full(); i++)  
      stk1.push((char) ('A' + i));  
 
    if(stk1.full()) Console.WriteLine("stk1 is full.");
 
    // Display the contents of stk1.
    Console.Write("Contents of stk1: ");  
    while( !stk1.empty() ) {   
      ch = stk1.pop();  
      Console.Write(ch);  
    }  
  
    Console.WriteLine();  
 
    if(stk1.empty()) Console.WriteLine("stk1 is empty.\n");
  
    // put more characters into stk1  
    Console.WriteLine("Again push A through J onto stk1.");
    for(i=0; !stk1.full(); i++)  
      stk1.push((char) ('A' + i));  
 
    /* Now, pop from stk1 and push the element in stk2.
       This causes stk2 to hold the elements in 
       reverse order. */
    Console.WriteLine("Now, pop chars from stk1 and push " +
                      "them onto stk2.");
    while( !stk1.empty() ) {   
      ch = stk1.pop();  
      stk2.push(ch);
    }  
 
    Console.Write("Contents of stk2: ");  
    while( !stk2.empty() ) {   
      ch = stk2.pop();  
      Console.Write(ch);  
    }  
 
    Console.WriteLine("\n");
 
    // put 5 characters into stack
    Console.WriteLine("Put 5 characters on stk3.");
    for(i=0; i < 5; i++)  
      stk3.push((char) ('A' + i));  
 
    Console.WriteLine("Capacity of stk3: " + stk3.capacity());
    Console.WriteLine("Number of objects in stk3: " +
                      stk3.getNum());
   
  }  
}

listing 4
// References can be passed to methods. 
 
using System;
 
class MyClass { 
  int alpha, beta;
 
  public MyClass(int i, int j) { 
    alpha = i; 
    beta = j; 
  } 
 
  /* Return true if ob contains the same values
     as the invoking object. */
  public bool sameAs(MyClass ob) { 
    if((ob.alpha == alpha) & (ob.beta == beta))
       return true; 
    else return false; 
  } 
 
  // Make a copy of ob.
  public void copy(MyClass ob) {
    alpha = ob.alpha;
    beta  = ob.beta;
  }
 
  public void show() {
    Console.WriteLine("alpha: {0}, beta: {1}",
                      alpha, beta);
  }

 
class PassOb { 
  public static void Main() {
    MyClass ob1 = new MyClass(4, 5); 
    MyClass ob2 = new MyClass(6, 7); 
 
    Console.Write("ob1: ");
    ob1.show();
 
    Console.Write("ob2: ");
    ob2.show();
 
    if(ob1.sameAs(ob2)) 
      Console.WriteLine("ob1 and ob2 have the same values.");
    else
      Console.WriteLine("ob1 and ob2 have different values.");
 
    Console.WriteLine();
 
    // now, make ob1 a copy of ob2
    ob1.copy(ob2);
 
    Console.Write("ob1 after copy: ");
    ob1.show();
 
    if(ob1.sameAs(ob2)) 
      Console.WriteLine("ob1 and ob2 have the same values.");
    else
      Console.WriteLine("ob1 and ob2 have different values.");
 
  } 
}

listing 5
// Value types are passed by value.
 
using System;
 
class Test {
  /* This method causes no change to the arguments
     used in the call. */
  public void noChange(int i, int j) {
    i = i + j;
    j = -j;
  }
}
 
class CallByValue {
  public static void Main() {
    Test ob = new Test();
 
    int a = 15, b = 20;
 
    Console.WriteLine("a and b before call: " +
                       a + " " + b);
 
    ob.noChange(a, b); 
 
    Console.WriteLine("a and b after call: " +
                       a + " " + b);
  }
}

listing 6
// Objects are passed by reference.
 
using System;
 
class Test {
  public int a, b;
 
  public Test(int i, int j) {
    a = i;
    b = j;
  }
 
  /* Pass an object. Now, ob.a and ob.b in object
     used in the call will be changed. */
  public void change(Test ob) {
    ob.a = ob.a + ob.b;
    ob.b = -ob.b;
  }
}
 
class CallByRef {
  public static void Main() {
    Test ob = new Test(15, 20);
 
    Console.WriteLine("ob.a and ob.b before call: " +
                       ob.a + " " + ob.b);
 
    ob.change(ob);
 
    Console.WriteLine("ob.a and ob.b after call: " +
                       ob.a + " " + ob.b);
  }
}

listing 7
// Use ref to pass a value type by reference.
 
using System;
 
class RefTest {
  /* This method changes its argument.
     Notice the use of ref. */
  public void sqr(ref int i) {
    i = i * i;
  }
}
 
class RefDemo {
  public static void Main() {
    RefTest ob = new RefTest();
 
    int a = 10;
 
    Console.WriteLine("a before call: " + a);
 
    ob.sqr(ref a); // notice the use of ref
 
    Console.WriteLine("a after call: " + a);
  }
}

listing 8
// Swap two values.
 
using System;
 
class Swap {
  // This method now changes its arguments.
  public void swap(ref int a, ref int b) {
    int t;
 
    t = a;
    a = b;
    b = t;
  }
}
 
class SwapDemo {
  public static void Main() {
    Swap ob = new Swap();
 
    int x = 10, y = 20;
 
    Console.WriteLine("x and y before call: " + x + " " + y);
 
    ob.swap(ref x, ref y); 
 
    Console.WriteLine("x and y after call: " + x + " " + y);
  }
}

listing 9
// Use out.
 
using System;
 
class Decompose {
 
  /* Decompose a floating-point value into its
      integer and fractional parts. */
  public int parts(double n, out double frac) {
    int whole;
 
    whole = (int) n;
    frac = n - whole; // pass fractional part back through frac
    return whole; // return integer portion
  }
}
 
class UseOut {
  public static void Main() {  
   Decompose ob = new Decompose();
    int i;
    double f;
 
    i = ob.parts(10.125, out f);
 
    Console.WriteLine("Integer portion is " + i);
    Console.WriteLine("Fractional part is " + f);
  }
}

listing 10
// Use two out parameters.
 
using System;
 
class Num {
  /* Determine if x and v have a common divisor.
     If so, return least and greatest common factors in 
     the out parameters. */
  public bool hasComFactor(int x, int y,
                           out int least, out int greatest) {
    int i;
    int max = x < y ? x : y;
    bool first = true;
 
    least = 1;
    greatest = 1; 
 
    // find least and greatest common factors
    for(i=2; i <= max/2 + 1; i++) {
      if( ((y%i)==0) & ((x%i)==0) ) {
        if(first) {
          least = i;
          first = false;
        }
        greatest = i;
      }
    }
 
    if(least != 1) return true;
    else return false;
  }
}
 
class DemoOut {
  public static void Main() {  
    Num ob = new Num();
    int lcf, gcf;
 
    if(ob.hasComFactor(231, 105, out lcf, out gcf)) {
      Console.WriteLine("Lcf of 231 and 105 is " + lcf);
      Console.WriteLine("Gcf of 231 and 105 is " + gcf);
    }
    else
      Console.WriteLine("No common factor for 35 and 49.");
 
    if(ob.hasComFactor(35, 51, out lcf, out gcf)) {
      Console.WriteLine("Lcf of 35 and 51 " + lcf);
      Console.WriteLine("Gcf of 35 and 51 is " + gcf);
    }
    else
      Console.WriteLine("No common factor for 35 and 51.");
 
  }
}

listing 11
// Swap two references.
 
using System;
 
class RefSwap {
  int a, b;
  
  public RefSwap(int i, int j) {
    a = i;
    b = j;
  }
 
  public void show() {
    Console.WriteLine("a: {0}, b: {1}", a, b);
  }
 
  // This method changes its arguments.
  public void swap(ref RefSwap ob1, ref RefSwap ob2) {
    RefSwap t;
 
    t = ob1;
    ob1 = ob2;
    ob2 = t;
  }
}
 
class RefSwapDemo {
  public static void Main() {
    RefSwap x = new RefSwap(1, 2);
    RefSwap y = new RefSwap(3, 4);
 
    Console.Write("x before call: ");
    x.show();
 
    Console.Write("y before call: ");
    y.show();
 
    Console.WriteLine();
 
    // exchange the objects to which x and y refer
    x.swap(ref x, ref y); 
 
    Console.Write("x after call: ");
    x.show();
 
    Console.Write("y after call: ");
    y.show();
 
  }
}

listing 12
// Demonstrate params.
 
using System;
 
class Min {
  public int minVal(params int[] nums) {
    int m;
 
    if(nums.Length == 0) {
      Console.WriteLine("Error: no arguments.");
      return 0;
    }
 
    m = nums[0];
    for(int i=1; i < nums.Length; i++) 
      if(nums[i] < m) m = nums[i];
 
    return m;
  }
}
 
class ParamsDemo {
  public static void Main() {
    Min ob = new Min();
    int min;
    int a = 10, b = 20;
 
    // call with two values
    min = ob.minVal(a, b);
    Console.WriteLine("Minimum is " + min);
 
    // call with 3 values
    min = ob.minVal(a, b, -1);
    Console.WriteLine("Minimum is " + min);
 
    // call with 5 values
    min = ob.minVal(18, 23, 3, 14, 25);
    Console.WriteLine("Minimum is " + min);
 
    // can call with an int array, too
    int[] args = { 45, 67, 34, 9, 112, 8 };
    min = ob.minVal(args);
    Console.WriteLine("Minimum is " + min);
  }
}

listing 13
// Use regular parameter with a params parameter.
 
using System;
 
class MyClass {
  public void showArgs(string msg, params int[] nums) {
    Console.Write(msg + ": ");
 
    foreach(int i in nums)
      Console.Write(i + " ");
 
    Console.WriteLine();
  }
}
 
class ParamsDemo2 {
  public static void Main() {
    MyClass ob = new MyClass();
 
    ob.showArgs("Here are some integers", 
                1, 2, 3, 4, 5);
 
    ob.showArgs("Here are two more", 
                17, 20);
 
  }
}

listing 14
// Return an object.
 
using System;
 
class Rect {
  int width;
  int height;
 
  public Rect(int w, int h) {
    width = w;
    height = h;
  }
 
  public int area() {
    return width * height;
  }
 
  public void show() {
    Console.WriteLine(width + " " + height);
  }
 
  /* Return a rectangle that is a specified
     factor larger than the invoking rectangle. */
  public Rect enlarge(int factor) {
    return new Rect(width * factor, height * factor);
  }
}
 
class RetObj {
  public static void Main() {  
    Rect r1 = new Rect(4, 5);
 
    Console.Write("Dimensions of r1: ");
    r1.show();
    Console.WriteLine("Area of r1: " + r1.area());
 
    Console.WriteLine();
 
    // create a rectangle that is twice as big as r1
    Rect r2 = r1.enlarge(2);
 
    Console.Write("Dimensions of r2: ");
    r2.show();
    Console.WriteLine("Area of r2 " + r2.area());
  }
}

listing 15
// Use a class factory.
 
using System;
 
class MyClass {
  int a, b; // private
 
  // Create a class factory for MyClass.
  public MyClass factory(int i, int j) {
    MyClass t = new MyClass();
   
    t.a = i;
    t.b = j;
 
    return t; // return an object
  }
 
  public void show() {
    Console.WriteLine("a and b: " + a + " " + b);
  }
 
}
 
class MakeObjects {
  public static void Main() {  
    MyClass ob = new MyClass();
    int i, j;
 
    // generate objects using the factory
    for(i=0, j=10; i < 10; i++, j--) {
      MyClass anotherOb = ob.factory(i, j); // make an object
      anotherOb.show();
    }
      
    Console.WriteLine();   
  }
}

listing 16
// Return an array.
 
using System;
 
class Factor {
  /* Return an array containing the factors of num.
     On return, numfactors will contain the number of
     factors found. */
  public int[] findfactors(int num, out int numfactors) {
    int[] facts = new int[80]; // size of 80 is arbitrary
    int i, j;
 
    // find factors and put them in the facts array
    for(i=2, j=0; i < num/2 + 1; i++) 
      if( (num%i)==0 ) {
        facts[j] = i;
        j++;
      }
    
    numfactors = j;
    return facts;
  }
}
 
class FindFactors {
  public static void Main() {  
    Factor f = new Factor();
    int numfactors;
    int[] factors;
 
    factors = f.findfactors(1000, out numfactors);
 
    Console.WriteLine("Factors for 1000 are: ");
    for(int i=0; i < numfactors; i++)
      Console.Write(factors[i] + " ");
      
    Console.WriteLine();   
  }
}

listing 17
// Demonstrate method overloading. 
 
using System;
 
class Overload { 
  public void ovlDemo() { 
    Console.WriteLine("No parameters"); 
  } 
 
  // Overload ovlDemo for one integer parameter. 
  public void ovlDemo(int a) { 
    Console.WriteLine("One parameter: " + a); 
  } 
 
  // Overload ovlDemo for two integer parameters. 
  public int ovlDemo(int a, int b) { 
    Console.WriteLine("Two parameters: " + a + " " + b); 
    return a + b;
  } 
 
  // Overload ovlDemo for two double parameters. 
  public double ovlDemo(double a, double b) {
    Console.WriteLine("Two double parameters: " +
                       a + " "+ b); 
    return a + b; 
  } 

 
class OverloadDemo { 
  public static void Main() { 
    Overload ob = new Overload(); 
    int resI;
    double resD;     
 
    // call all versions of ovlDemo() 
    ob.ovlDemo();  
    Console.WriteLine();
 
    ob.ovlDemo(2); 
    Console.WriteLine();
 
    resI = ob.ovlDemo(4, 6); 
    Console.WriteLine("Result of ob.ovlDemo(4, 6): " +
                       resI); 
    Console.WriteLine();
 
 
    resD = ob.ovlDemo(1.1, 2.32); 
    Console.WriteLine("Result of ob.ovlDemo(1.1, 2.32): " +
                       resD); 
  } 
}

listing 18
/* Automatic type conversions can affect
   overloaded method resolution. */
 
using System;
 
class Overload2 {
  public void f(int x) {
    Console.WriteLine("Inside f(int): " + x);
  }
 
  public void f(double x) {
    Console.WriteLine("Inside f(double): " + x);
  }
}
 
class TypeConv {
  public static void Main() {
    Overload2 ob = new Overload2();
 
    int i = 10;
    double d = 10.1;
 
    byte b = 99;
    short s = 10;
    float f = 11.5F;
 
 
    ob.f(i); // calls ob.f(int)
    ob.f(d); // calls ob.f(double)
 
    ob.f(b); // calls ob.f(int) -- type conversion
    ob.f(s); // calls ob.f(int) -- type conversion
    ob.f(f); // calls ob.f(double) -- type conversion
  }
}

listing 19
// Add f(byte).
 
using System;
 
class Overload2 {
  public void f(byte x) {
    Console.WriteLine("Inside f(byte): " + x);
  }
 
  public void f(int x) {
    Console.WriteLine("Inside f(int): " + x);
  }
 
  public void f(double x) {
    Console.WriteLine("Inside f(double): " + x);
  }
}
 
class TypeConv {
  public static void Main() {
    Overload2 ob = new Overload2();
 
    int i = 10;
    double d = 10.1;
 
    byte b = 99;
    short s = 10;
    float f = 11.5F;
 
 
    ob.f(i); // calls ob.f(int)
    ob.f(d); // calls ob.f(double)
 
    ob.f(b); // calls ob.f(byte) -- now, no type conversion
 
    ob.f(s); // calls ob.f(int) -- type conversion
    ob.f(f); // calls ob.f(double) -- type conversion
  }
}

listing 20
// Demonstrate an overloaded constructor.
 
using System;
 
class MyClass { 
  public int x; 
 
  public MyClass() {
    Console.WriteLine("Inside MyClass().");
    x = 0;
  }
 
  public MyClass(int i) { 
    Console.WriteLine("Inside MyClass(int).");
    x = i; 
  }
 
  public MyClass(double d) {
    Console.WriteLine("Inside MyClass(double).");
    x = (int) d;
  }
 
  public MyClass(int i, int j) {
    Console.WriteLine("Inside MyClass(int, int).");
    x = i * j;
  }   
}   
   
class OverloadConsDemo {   
  public static void Main() {   
    MyClass t1 = new MyClass(); 
    MyClass t2 = new MyClass(88); 
    MyClass t3 = new MyClass(17.23); 
    MyClass t4 = new MyClass(2, 4); 
 
    Console.WriteLine("t1.x: " + t1.x);
    Console.WriteLine("t2.x: " + t2.x);
    Console.WriteLine("t3.x: " + t3.x);
    Console.WriteLine("t4.x: " + t4.x);
  }
}

listing 21
// A stack class for characters.  
 
using System; 
 
class Stack {  
  // these members are private
  char[] stck; // holds the stack 
  int tos;     // index of the top of the stack 
  
  // Construct an empty Stack given its size. 
  public Stack(int size) {  
    stck = new char[size]; // allocate memory for stack 
    tos = 0;  
  }  
 
  // Construct a Stack from a stack.
  public Stack(Stack ob) {  
    // allocate memory for stack 
    stck = new char[ob.stck.Length];
 
    // copy elements to new stack
    for(int i=0; i < ob.tos; i++) 
      stck[i] = ob.stck[i];
 
    // set tos for new stack
    tos = ob.tos;
  }  
 
  // Push characters onto the stack. 
  public void push(char ch) {  
    if(tos==stck.Length) {  
      Console.WriteLine(" -- Stack is full.");  
      return;  
    }  
      
    stck[tos] = ch; 
    tos++; 
  }  
  
  // Pop a character from the stack. 
  public char pop() {  
    if(tos==0) {  
      Console.WriteLine(" -- Stack is empty.");  
      return (char) 0;   
    }  
    
    tos--;  
    return stck[tos];  
  }
 
  // Return true if the stack is full.
  public bool full() {
    return tos==stck.Length;   
  }
 
  // Return true if the stack is empty.
  public bool empty() {
    return tos==0;
  }
 
  // Return total capacity of the stack.
  public int capacity() {
    return stck.Length;
  }
 
  // Return number of objects currently on the stack.
  public int getNum() {
    return tos;
  }
}
 
// Demonstrate the Stack class.  
class StackDemo {  
  public static void Main() {  
    Stack stk1 = new Stack(10);  
    char ch;  
    int i;  
  
    // Put some characters into stk1.
    Console.WriteLine("Push A through J onto stk1.");
    for(i=0; !stk1.full(); i++)  
      stk1.push((char) ('A' + i));  
 
    // Create a copy of stck1
    Stack stk2 = new Stack(stk1);
 
    // Display the contents of stk1.
    Console.Write("Contents of stk1: ");  
    while( !stk1.empty() ) {   
      ch = stk1.pop();  
      Console.Write(ch);  
    }  
 
    Console.WriteLine();
  
    Console.Write("Contents of stk2: ");  
    while ( !stk2.empty() ) {   
      ch = stk2.pop();  
      Console.Write(ch);  
    }  
 
    Console.WriteLine("\n");
   
  }  
}

listing 22
// Demonstrate invoking a constructor through this.
 
using System; 
 
class XYCoord {  
  public int x, y;  
  
  public XYCoord() : this(0, 0) {
    Console.WriteLine("Inside XYCoord()");
  } 
 
  public XYCoord(XYCoord obj) : this(obj.x, obj.y) {
    Console.WriteLine("Inside XYCoord(obj)");
  } 
 
  public XYCoord(int i, int j) { 
    Console.WriteLine("Inside XYCoord(int, int)");
    x = i;
    y = j;
  }    
}    
    
class OverloadConsDemo {    
  public static void Main() {    
    XYCoord t1 = new XYCoord();  
    XYCoord t2 = new XYCoord(8, 9);  
    XYCoord t3 = new XYCoord(t2);  
  
    Console.WriteLine("t1.x, t1.y: " + t1.x + ", " + t1.y); 
    Console.WriteLine("t2.x, t2.y: " + t2.x + ", " + t2.y); 
    Console.WriteLine("t3.x, t3.y: " + t3.x + ", " + t3.y); 
  }    
}

listing 23
// Display all command-line information.
 
using System;
 
class CLDemo { 
  public static void Main(string[] args) {
    Console.WriteLine("There are " + args.Length +
                       " command-line arguments.");
 
    Console.WriteLine("They are: ");
    for(int i=0; i < args.Length; i++) 
      Console.WriteLine(args[i]); 
  } 
}

listing 24
// Encode or decode a message.
 
using System;
 
class Cipher {
  public static int Main(string[] args) {  
 
    // see if arguments are present
    if(args.Length < 2) {
      Console.WriteLine("Usage: encode/decode word1 [word2...wordN]");
      return 1; // return failure code
    }
 
    // if args present, first arg must be encode or decode
    if(args[0] != "encode" & args[0] != "decode") {
      Console.WriteLine("First arg must be encode or decode.");
      return 1; // return failure code
    }
 
    // encode or decode message
    for(int n=1; n < args.Length; n++) {
      for(int i=0; i < args[n].Length; i++) {
        if(args[0] == "encode")
          Console.Write((char) (args[n][i] + 1) );
        else 
          Console.Write((char) (args[n][i] - 1) );
      }
      Console.Write(" ");
    }
 
    Console.WriteLine();
 
    return 0;
  }
}

listing 25
// A simple example of recursion. 
 
using System;
 
class Factorial { 
  // This is a recursive function. 
  public int factR(int n) { 
    int result; 
 
    if(n==1) return 1; 
    result = factR(n-1) * n; 
    return result; 
  } 
 
  // This is an iterative equivalent. 
  public int factI(int n) { 
    int t, result; 
 
    result = 1; 
    for(t=1; t <= n; t++) result *= t; 
    return result; 
  } 

 
class Recursion { 
  public static void Main() { 
    Factorial f = new Factorial(); 
 
    Console.WriteLine("Factorials using recursive method."); 
    Console.WriteLine("Factorial of 3 is " + f.factR(3)); 
    Console.WriteLine("Factorial of 4 is " + f.factR(4)); 
    Console.WriteLine("Factorial of 5 is " + f.factR(5)); 
    Console.WriteLine(); 
 
    Console.WriteLine("Factorials using iterative method."); 
    Console.WriteLine("Factorial of 3 is " + f.factI(3)); 
    Console.WriteLine("Factorial of 4 is " + f.factI(4)); 
    Console.WriteLine("Factorial of 5 is " + f.factI(5)); 
  } 
}

listing 26
// Display a string in reverse by using recursion.
 
using System;
 
class RevStr {
 
  // Display a string backwards.
  public void displayRev(string str) {
    if(str.Length > 0) 
      displayRev(str.Substring(1, str.Length-1));
    else 
      return;
 
    Console.Write(str[0]);
  }
}
 
class RevStrDemo {
  public static void Main() {  
    string s = "this is a test";
    RevStr rsOb = new RevStr();
 
    Console.WriteLine("Original string: " + s);
 
    Console.Write("Reversed string: ");
    rsOb.displayRev(s);
 
    Console.WriteLine();
  }
}

listing 27
// Use static.
 
using System;
 
class StaticDemo {
  // a static variable
  public static int val = 100; 
 
  // a static method
  public static int valDiv2() {
    return val/2;
  }
}
 
class SDemo {
  public static void Main() {
 
    Console.WriteLine("Initial value of StaticDemo.val is "
                      + StaticDemo.val);
 
    StaticDemo.val = 8;
    Console.WriteLine("StaticDemo.val is " + StaticDemo.val);
    Console.WriteLine("StaticDemo.valDiv2(): " +
                       StaticDemo.valDiv2());
  }
}

listing 28
class StaticError {
  int denom = 3; // a normal instance variable
  static int val = 1024; // a static variable
 
  /* Error! Can't directly access a non-static variable
     from within a static method. */
  static int valDivDenom() {
    return val/denom; // won't compile!
  }
}

listing 29
using System;
 
class AnotherStaticError {
  // non-static method.
  void nonStaticMeth() {
     Console.WriteLine("Inside nonStaticMeth().");
  }
 
  /* Error! Can't directly call a non-static method
     from within a static method. */
  static void staticMeth() {
    nonStaticMeth(); // won't compile
  }
}

listing 30
class MyClass {
  // non-static method.
  void nonStaticMeth() {
     Console.WriteLine("Inside nonStaticMeth().");
  }
 
  /* Can call a non-static method through an
     object reference from within a static method. */
  public static void staticMeth(MyClass ob) {
    ob.nonStaticMeth(); // this is OK
  }
}

listing 31
// Use a static field to count instances.
 
using System;
 
class CountInst { 
  static int count = 0;
 
  // increment count when object is created
  public CountInst() { 
    count++;
  } 
 
  // decrement count when object is destroyed
  ~CountInst() {
    count--;
  }
 
  public static int getcount() {
    return count;
  }

 
class CountDemo { 
  public static void Main() {
    CountInst ob;
 
 
    for(int i=0; i < 10; i++) {
      ob = new CountInst();
      Console.WriteLine("Current count: " + 
                        CountInst.getcount());
    }
 
  } 
}

listing 32
// Use a static class factory.
 
using System;
 
class MyClass {
  int a, b;
 
  // Create a class factory for MyClass.
  static public MyClass factory(int i, int j) {
    MyClass t = new MyClass();
   
    t.a = i;
    t.b = j;
 
    return t; // return an object
  }
 
  public void show() {
    Console.WriteLine("a and b: " + a + " " + b);
  }
 
}
 
class MakeObjects {
  public static void Main() {  
    int i, j;
 
    // generate objects using the factory
    for(i=0, j=10; i < 10; i++, j--) {
      MyClass ob = MyClass.factory(i, j); // get an object
      ob.show();
    }
      
    Console.WriteLine();   
  }
}

listing 33
// Use a static constructor.
 
using System;
 
class Cons {
  public static int alpha;
  public int beta;
 
  // static constructor
  static Cons() {
    alpha = 99;
    Console.WriteLine("Inside static constructor.");
  }
 
  // instance constructor
  public Cons() {
    beta = 100;
    Console.WriteLine("Inside instance constructor.");
  }
}
 
class ConsDemo {
  public static void Main() {  
    Cons ob = new Cons();
 
    Console.WriteLine("Cons.alpha: " + Cons.alpha);
    Console.WriteLine("ob.beta: " + ob.beta);
  }
}

listing 34
// Demonstrate a static class.
 
using System; 
 
static class NumericFn { 
  // Return the reciprocal of a value.
  static public double reciprocal(double num) {
    return 1/num;
  }
 
  // Return the fractional part of a value.
  static public double fracPart(double num) {
    return num - (int) num;
  }
 
  // Return true if num is even.
  static public bool isEven(double num) {
    return (num % 2) == 0 ? true : false;
  }
 
  // Return true of num is odd.
  static public bool isOdd(double num) {
    return !isEven(num);
  }
 

 
class StaticClassDemo { 
  public static void Main() {   
    Console.WriteLine("Reciprocal of 5 is " +
                      NumericFn.reciprocal(5.0));
 
    Console.WriteLine("Fractional part of 4.234 is " +
                      NumericFn.fracPart(4.234));
 
    if(NumericFn.isEven(10))
      Console.WriteLine("10 is even.");
 
    if(NumericFn.isOdd(5))
      Console.WriteLine("5 is odd.");
 
    // The following attempt to create an instance of 
    // NumericFn will cause an error.
//  NumericFn ob = new NumericFn(); // Wrong!
  } 
}

listing 1
// An example of operator overloading.
 
using System;
 
// A three-dimensional coordinate class.
class ThreeD {
  int x, y, z; // 3-D coordinates  
 
  public ThreeD() { x = y = z = 0; }
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }
 
  // Overload binary +.
  public static ThreeD operator +(ThreeD op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    /* This adds together the coordinates of the two points
       and returns the result. */
    result.x = op1.x + op2.x; // These are integer additions
    result.y = op1.y + op2.y; // and the + retains its original
    result.z = op1.z + op2.z; // meaning relative to them.
 
    return result;
  }
 
  // Overload binary -.
  public static ThreeD operator -(ThreeD op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    /* Notice the order of the operands. op1 is the left
       operand and op2 is the right. */
    result.x = op1.x - op2.x; // these are integer subtractions
    result.y = op1.y - op2.y; 
    result.z = op1.z - op2.z; 
 
    return result;
  }
  
  // Show X, Y, Z coordinates.
  public void show()
  {
    Console.WriteLine(x + ", " + y + ", " + z);
  }
}
 
class ThreeDDemo {
  public static void Main() {
    ThreeD a = new ThreeD(1, 2, 3);
    ThreeD b = new ThreeD(10, 10, 10);
    ThreeD c = new ThreeD();
 
    Console.Write("Here is a: ");
    a.show();
    Console.WriteLine();
    Console.Write("Here is b: ");
    b.show();
    Console.WriteLine();
 
    c = a + b; // add a and b together
    Console.Write("Result of a + b: ");
    c.show();
    Console.WriteLine();
 
    c = a + b + c; // add a, b and c together
    Console.Write("Result of a + b + c: ");
    c.show();
    Console.WriteLine();
 
    c = c - a; // subtract a
    Console.Write("Result of c - a: ");
    c.show();
    Console.WriteLine();
 
    c = c - b; // subtract b
    Console.Write("Result of c - b: ");
    c.show();
    Console.WriteLine();
  }
}

listing 2
// More operator overloading.
 
using System;
 
// A three-dimensional coordinate class.
class ThreeD {
  int x, y, z; // 3-D coordinates  
 
  public ThreeD() { x = y = z = 0; }
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }
 
  // Overload binary +.
  public static ThreeD operator +(ThreeD op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    /* This adds together the coordinates of the two points
       and returns the result. */
    result.x = op1.x + op2.x; 
    result.y = op1.y + op2.y; 
    result.z = op1.z + op2.z; 
 
    return result;
  }
 
  // Overload binary -.
  public static ThreeD operator -(ThreeD op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    /* Notice the order of the operands. op1 is the left
       operand and op2 is the right. */
    result.x = op1.x - op2.x; 
    result.y = op1.y - op2.y; 
    result.z = op1.z - op2.z; 
 
    return result;
  }
  
  // Overload unary -.
  public static ThreeD operator -(ThreeD op)
  {
    ThreeD result = new ThreeD();
 
    result.x = -op.x;
    result.y = -op.y; 
    result.z = -op.z; 
 
    return result;
  }
 
  // Overload unary ++.
  public static ThreeD operator ++(ThreeD op)
  {
    // for ++, modify argument
    op.x++;
    op.y++; 
    op.z++; 
 
    return op;
  }
 
  // Show X, Y, Z coordinates.
  public void show()
  {
    Console.WriteLine(x + ", " + y + ", " + z);
  }
}
 
class ThreeDDemo {
  public static void Main() {
    ThreeD a = new ThreeD(1, 2, 3);
    ThreeD b = new ThreeD(10, 10, 10);
    ThreeD c = new ThreeD();
 
    Console.Write("Here is a: ");
    a.show();
    Console.WriteLine();
    Console.Write("Here is b: ");
    b.show();
    Console.WriteLine();
 
    c = a + b; // add a and b together
    Console.Write("Result of a + b: ");
    c.show();
    Console.WriteLine();
 
    c = a + b + c; // add a, b and c together
    Console.Write("Result of a + b + c: ");
    c.show();
    Console.WriteLine();
 
    c = c - a; // subtract a
    Console.Write("Result of c - a: ");
    c.show();
    Console.WriteLine();
 
    c = c - b; // subtract b
    Console.Write("Result of c - b: ");
    c.show();
    Console.WriteLine();
 
    c = -a; // assign -a to c
    Console.Write("Result of -a: ");
    c.show();
    Console.WriteLine();
 
    a++; // increment a
    Console.Write("Result of a++: ");
    a.show();  
  }
}

listing 3
/* Overload addition for object + object, and
   for object + int. */
 
using System;
 
// A three-dimensional coordinate class.
class ThreeD {
  int x, y, z; // 3-D coordinates  
 
  public ThreeD() { x = y = z = 0; }
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }
 
  // Overload binary + for object + object.
  public static ThreeD operator +(ThreeD op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    /* This adds together the coordinates of the two points
       and returns the result. */
    result.x = op1.x + op2.x; 
    result.y = op1.y + op2.y; 
    result.z = op1.z + op2.z; 
 
    return result;
  }
 
  // Overload binary + for object + int.
  public static ThreeD operator +(ThreeD op1, int op2)
  {
    ThreeD result = new ThreeD();
 
    result.x = op1.x + op2;
    result.y = op1.y + op2;
    result.z = op1.z + op2;
 
    return result;
  }
 
  // Show X, Y, Z coordinates.
  public void show()
  {
    Console.WriteLine(x + ", " + y + ", " + z);
  }
}
 
class ThreeDDemo {
  public static void Main() {
    ThreeD a = new ThreeD(1, 2, 3);
    ThreeD b = new ThreeD(10, 10, 10);
    ThreeD c = new ThreeD();
 
    Console.Write("Here is a: ");
    a.show();
    Console.WriteLine();
    Console.Write("Here is b: ");
    b.show();
    Console.WriteLine();
 
    c = a + b; // object + object
    Console.Write("Result of a + b: ");
    c.show();
    Console.WriteLine();
 
    c = b + 10; // object + int
    Console.Write("Result of b + 10: ");
    c.show();
  }
}

listing 4
/* Overload the + for object + object,
   object + int, and int + object. */
 
using System;
 
// A three-dimensional coordinate class.
class ThreeD {
  int x, y, z; // 3-D coordinates  
 
  public ThreeD() { x = y = z = 0; }
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }
 
  // Overload binary + for object + object.
  public static ThreeD operator +(ThreeD op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    /* This adds together the coordinates of the two points
       and returns the result. */
    result.x = op1.x + op2.x; 
    result.y = op1.y + op2.y; 
    result.z = op1.z + op2.z; 
 
    return result;
  }
 
  // Overload binary + for object + int.
  public static ThreeD operator +(ThreeD op1, int op2)
  {
    ThreeD result = new ThreeD();
 
    result.x = op1.x + op2;
    result.y = op1.y + op2;
    result.z = op1.z + op2;
 
    return result;
  }
 
  // Overload binary + for int + object.
  public static ThreeD operator +(int op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    result.x = op2.x + op1;
    result.y = op2.y + op1;
    result.z = op2.z + op1;
 
    return result;
  }
 
  // Show X, Y, Z coordinates.
  public void show()
  {
    Console.WriteLine(x + ", " + y + ", " + z);
  }
}
 
class ThreeDDemo {
  public static void Main() {
    ThreeD a = new ThreeD(1, 2, 3);
    ThreeD b = new ThreeD(10, 10, 10);
    ThreeD c = new ThreeD();
 
    Console.Write("Here is a: ");
    a.show();
    Console.WriteLine();
    Console.Write("Here is b: ");
    b.show();
    Console.WriteLine();
 
    c = a + b; // object + object
    Console.Write("Result of a + b: ");
    c.show();
    Console.WriteLine();
 
    c = b + 10; // object + int
    Console.Write("Result of b + 10: ");
    c.show();
    Console.WriteLine();
 
    c = 15 + b; // int + object
    Console.Write("Result of 15 + b: ");
    c.show();
  }
}

listing 5
// Overload < and >.  
 
using System; 
 
// A three-dimensional coordinate class. 
class ThreeD { 
  int x, y, z; // 3-D coordinates   
 
  public ThreeD() { x = y = z = 0; } 
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; } 
 
  // Overload <. 
  public static bool operator <(ThreeD op1, ThreeD op2) 
  { 
    if((op1.x < op2.x) && (op1.y < op2.y) && (op1.z < op2.z)) 
      return true; 
    else 
      return false; 
  } 
 
  // Overload >. 
  public static bool operator >(ThreeD op1, ThreeD op2) 
  { 
    if((op1.x > op2.x) && (op1.y > op2.y) && (op1.z > op2.z)) 
      return true; 
    else 
      return false; 
  } 
 
  // Show X, Y, Z coordinates. 
  public void show() 
  { 
    Console.WriteLine(x + ", " + y + ", " + z); 
  } 

 
class ThreeDDemo { 
  public static void Main() { 
    ThreeD a = new ThreeD(5, 6, 7); 
    ThreeD b = new ThreeD(10, 10, 10); 
    ThreeD c = new ThreeD(1, 2, 3); 
 
    Console.Write("Here is a: "); 
    a.show(); 
    Console.Write("Here is b: "); 
    b.show(); 
    Console.Write("Here is c: "); 
    c.show(); 
    Console.WriteLine(); 
 
    if(a > c) Console.WriteLine("a > c is true"); 
    if(a < c) Console.WriteLine("a < c is true"); 
    if(a > b) Console.WriteLine("a > b is true"); 
    if(a < b) Console.WriteLine("a < b is true"); 
  } 
}

listing 6
// Overload true and false for ThreeD.
 
using System;  
  
// A three-dimensional coordinate class.  
class ThreeD {  
  int x, y, z; // 3-D coordinates    
  
  public ThreeD() { x = y = z = 0; }  
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }  
 
  // Overload true.  
  public static bool operator true(ThreeD op) {
    if((op.x != 0) || (op.y != 0) || (op.z != 0))
      return true; // at least one coordinate is non-zero
    else
      return false;
  }  
 
  // Overload false.
  public static bool operator false(ThreeD op) {
    if((op.x == 0) && (op.y == 0) && (op.z == 0))
      return true; // all coordinates are zero
    else
      return false;
  }  
 
  // Overload unary --. 
  public static ThreeD operator --(ThreeD op) 
  { 
    // for ++, modify argument 
    op.x--; 
    op.y--;  
    op.z--;  
 
    return op; 
  } 
 
  // Show X, Y, Z coordinates.  
  public void show()  
  {  
    Console.WriteLine(x + ", " + y + ", " + z);  
  }  
}  
  
class TrueFalseDemo {  
  public static void Main() {  
    ThreeD a = new ThreeD(5, 6, 7);  
    ThreeD b = new ThreeD(10, 10, 10);  
    ThreeD c = new ThreeD(0, 0, 0);  
  
    Console.Write("Here is a: ");  
    a.show();  
    Console.Write("Here is b: ");  
    b.show();  
    Console.Write("Here is c: ");  
    c.show();  
    Console.WriteLine();  
  
    if(a) Console.WriteLine("a is true.");
    else Console.WriteLine("a is false.");
 
    if(b) Console.WriteLine("b is true.");
    else Console.WriteLine("b is false.");
 
    if(c) Console.WriteLine("c is true.");
    else Console.WriteLine("c is false.");
 
    Console.WriteLine();
 
    Console.WriteLine("Control a loop using a ThreeD object.");
    do {
      b.show();
      b--;
    } while(b);
 
  }  
}

listing 7
// A simple way to overload !, |, and & for ThreeD.
 
using System;  
  
// A three-dimensional coordinate class.  
class ThreeD {  
  int x, y, z; // 3-D coordinates    
  
  public ThreeD() { x = y = z = 0; }  
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }  
 
 
  // Overload |.  
  public static bool operator |(ThreeD op1, ThreeD op2)  
  { 
    if( ((op1.x != 0) || (op1.y != 0) || (op1.z != 0)) |
       ((op2.x != 0) || (op2.y != 0) || (op2.z != 0)) )
      return true;  
    else  
      return false;  
  }  
 
  // Overload &.  
  public static bool operator &(ThreeD op1, ThreeD op2)  
  {  
    if( ((op1.x != 0) && (op1.y != 0) && (op1.z != 0)) &
       ((op2.x != 0) && (op2.y != 0) && (op2.z != 0)) )
      return true;  
    else  
      return false;  
  }  
 
  // Overload !.  
  public static bool operator !(ThreeD op)  
  {  
    if((op.x != 0) || (op.y != 0) || (op.z != 0))
      return false;
    else return true;  
  }  
 
  // Show X, Y, Z coordinates.  
  public void show()  
  {  
    Console.WriteLine(x + ", " + y + ", " + z);  
  }  
}  
  
class TrueFalseDemo {  
  public static void Main() {  
    ThreeD a = new ThreeD(5, 6, 7);  
    ThreeD b = new ThreeD(10, 10, 10);  
    ThreeD c = new ThreeD(0, 0, 0);  
  
    Console.Write("Here is a: ");  
    a.show();  
    Console.Write("Here is b: ");  
    b.show();  
    Console.Write("Here is c: ");  
    c.show();  
    Console.WriteLine();  
 
    if(!a) Console.WriteLine("a is false.");
    if(!b) Console.WriteLine("b is false.");
    if(!c) Console.WriteLine("c is false.");
 
    Console.WriteLine();
 
    if(a & b) Console.WriteLine("a & b is true.");
    else Console.WriteLine("a & b is false.");
 
    if(a & c) Console.WriteLine("a & c is true.");
    else Console.WriteLine("a & c is false.");
 
    if(a | b) Console.WriteLine("a | b is true.");
    else Console.WriteLine("a | b is false.");
 
    if(a | c) Console.WriteLine("a | c is true.");
    else Console.WriteLine("a | c is false.");
  }  
}

listing 8
/* A better way to overload !, |, and & for ThreeD.
   This version automatically enables the && and || operators. */
 
using System;  
  
// A three-dimensional coordinate class.  
class ThreeD {  
  int x, y, z; // 3-D coordinates    
  
  public ThreeD() { x = y = z = 0; }  
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }  
 
 
  // Overload | for short-circuit evaluation.  
  public static ThreeD operator |(ThreeD op1, ThreeD op2)  
  { 
    if( ((op1.x != 0) || (op1.y != 0) || (op1.z != 0)) |
       ((op2.x != 0) || (op2.y != 0) || (op2.z != 0)) )
      return new ThreeD(1, 1, 1);  
    else  
      return new ThreeD(0, 0, 0);  
  }  
 
  // Overload & for short-circuit evaluation.  
  public static ThreeD operator &(ThreeD op1, ThreeD op2)  
  {  
    if( ((op1.x != 0) && (op1.y != 0) && (op1.z != 0)) &
       ((op2.x != 0) && (op2.y != 0) && (op2.z != 0)) )
      return new ThreeD(1, 1, 1);  
    else  
      return new ThreeD(0, 0, 0);  
  }  
 
  // Overload !.  
  public static bool operator !(ThreeD op)  
  {  
    if(op) return false;  
    else return true;  
  }  
 
  // Overload true.  
  public static bool operator true(ThreeD op) {
    if((op.x != 0) || (op.y != 0) || (op.z != 0))
      return true; // at least one coordinate is non-zero
    else
      return false;
  }  
 
  // Overload false.
  public static bool operator false(ThreeD op) {
    if((op.x == 0) && (op.y == 0) && (op.z == 0))
      return true; // all coordinates are zero
    else
      return false;
  }  
 
  // Show X, Y, Z coordinates.  
  public void show()  
  {  
    Console.WriteLine(x + ", " + y + ", " + z);  
  }  
}  
  
class TrueFalseDemo {  
  public static void Main() {  
    ThreeD a = new ThreeD(5, 6, 7);  
    ThreeD b = new ThreeD(10, 10, 10);  
    ThreeD c = new ThreeD(0, 0, 0);  
  
    Console.Write("Here is a: ");  
    a.show();  
    Console.Write("Here is b: ");  
    b.show();  
    Console.Write("Here is c: ");  
    c.show();  
    Console.WriteLine();  
  
    if(a) Console.WriteLine("a is true.");
    if(b) Console.WriteLine("b is true.");
    if(c) Console.WriteLine("c is true.");
 
    if(!a) Console.WriteLine("a is false.");
    if(!b) Console.WriteLine("b is false.");
    if(!c) Console.WriteLine("c is false.");
 
    Console.WriteLine();
 
    Console.WriteLine("Use & and |");
    if(a & b) Console.WriteLine("a & b is true.");
    else Console.WriteLine("a & b is false.");
 
    if(a & c) Console.WriteLine("a & c is true.");
    else Console.WriteLine("a & c is false.");
 
    if(a | b) Console.WriteLine("a | b is true.");
    else Console.WriteLine("a | b is false.");
 
    if(a | c) Console.WriteLine("a | c is true.");
    else Console.WriteLine("a | c is false.");
 
    Console.WriteLine();
 
    // now use short-circuit ops
    Console.WriteLine("Use short-circuit && and ||");
    if(a && b) Console.WriteLine("a && b is true.");
    else Console.WriteLine("a && b is false.");
 
    if(a && c) Console.WriteLine("a && c is true.");
    else Console.WriteLine("a && c is false.");
 
    if(a || b) Console.WriteLine("a || b is true.");
    else Console.WriteLine("a || b is false.");
 
    if(a || c) Console.WriteLine("a || c is true.");
    else Console.WriteLine("a || c is false.");
  }  
}

listing 9
// An example that uses an implicit conversion operator.
 
using System;
 
// A three-dimensional coordinate class.
class ThreeD {
  int x, y, z; // 3-D coordinates  
 
  public ThreeD() { x = y = z = 0; }
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }
 
  // Overload binary +.
  public static ThreeD operator +(ThreeD op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    result.x = op1.x + op2.x; 
    result.y = op1.y + op2.y; 
    result.z = op1.z + op2.z; 
 
    return result;
  }
 
  // An implicit conversion from ThreeD to int.
  public static implicit operator int(ThreeD op1)
  {
    return op1.x * op1.y * op1.z;
  }
  
  // Show X, Y, Z coordinates.
  public void show()
  {
    Console.WriteLine(x + ", " + y + ", " + z);
  }
}
 
class ThreeDDemo {
  public static void Main() {
    ThreeD a = new ThreeD(1, 2, 3);
    ThreeD b = new ThreeD(10, 10, 10);
    ThreeD c = new ThreeD();
    int i;
 
    Console.Write("Here is a: ");
    a.show();
    Console.WriteLine();
    Console.Write("Here is b: ");
    b.show();
    Console.WriteLine();
 
    c = a + b; // add a and b together
    Console.Write("Result of a + b: ");
    c.show();
    Console.WriteLine();
 
    i = a; // convert to int
    Console.WriteLine("Result of i = a: " + i);
    Console.WriteLine();
 
    i = a * 2 - b; // convert to int
    Console.WriteLine("result of a * 2 - b: " + i);
  }
}

listing 10
// Use an explicit conversion.
 
using System;
 
// A three-dimensional coordinate class.
class ThreeD {
  int x, y, z; // 3-D coordinates  
 
  public ThreeD() { x = y = z = 0; }
  public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }
 
  // Overload binary +.
  public static ThreeD operator +(ThreeD op1, ThreeD op2)
  {
    ThreeD result = new ThreeD();
 
    result.x = op1.x + op2.x; 
    result.y = op1.y + op2.y; 
    result.z = op1.z + op2.z; 
 
    return result;
  }
 
  // This is now explicit.
  public static explicit operator int(ThreeD op1)
  {
    return op1.x * op1.y * op1.z;
  }
  
  // Show X, Y, Z coordinates.
  public void show()
  {
    Console.WriteLine(x + ", " + y + ", " + z);
  }
}
 
class ThreeDDemo {
  public static void Main() {
    ThreeD a = new ThreeD(1, 2, 3);
    ThreeD b = new ThreeD(10, 10, 10);
    ThreeD c = new ThreeD();
    int i;
 
    Console.Write("Here is a: ");
    a.show();
    Console.WriteLine();
    Console.Write("Here is b: ");
    b.show();
    Console.WriteLine();
 
    c = a + b; // add a and b together
    Console.Write("Result of a + b: ");
    c.show();
    Console.WriteLine();
 
    i = (int) a; // explicitly convert to int -- cast required
    Console.WriteLine("Result of i = a: " + i);
    Console.WriteLine();
 
    i = (int)a * 2 - (int)b; // casts required
    Console.WriteLine("result of a * 2 - b: " + i);
 
  }
}

listing 11
// Create a 4-bit type called Nybble.
 
using System; 
 
// A 4-bit type.
class Nybble { 
  int val; // underlying storage
 
  public Nybble() { val = 0; } 
 
  public Nybble(int i) {
    val = i;
    val = val & 0xF; // retain lower 4 bits
  }
 
  // Overload binary + for Nybble + Nybble. 
  public static Nybble operator +(Nybble op1, Nybble op2) 
  { 
    Nybble result = new Nybble(); 
 
    result.val = op1.val + op2.val; 
 
    result.val = result.val & 0xF; // retain lower 4 bits 
 
    return result; 
  } 
 
  // Overload binary + for Nybble + int. 
  public static Nybble operator +(Nybble op1, int op2) 
  { 
    Nybble result = new Nybble(); 
 
    result.val = op1.val + op2; 
 
    result.val = result.val & 0xF; // retain lower 4 bits 
 
    return result; 
  } 
 
  // Overload binary + for int + Nybble. 
  public static Nybble operator +(int op1, Nybble op2) 
  { 
    Nybble result = new Nybble(); 
 
    result.val = op1 + op2.val; 
 
    result.val = result.val & 0xF; // retain lower 4 bits 
 
    return result; 
  } 
 
  // Overload ++.
  public static Nybble operator ++(Nybble op)
  {
    op.val++;
 
    op.val = op.val & 0xF; // retain lower 4 bits
 
    return op;
  }
 
  // Overload >.
  public static bool operator >(Nybble op1, Nybble op2)
  {
    if(op1.val > op2.val) return true;
    else return false;
  }
 
  // Overload <.
  public static bool operator <(Nybble op1, Nybble op2)
  {
    if(op1.val < op2.val) return true;
    else return false;
  }
 
  // Convert a Nybble into an int.
  public static implicit operator int (Nybble op)
  {
    return op.val;
  }
 
  // Convert an int into a Nybble.
  public static implicit operator Nybble (int op)
  {
    return new Nybble(op);
  }

 
class NybbleDemo { 
  public static void Main() { 
    Nybble a = new Nybble(1); 
    Nybble b = new Nybble(10); 
    Nybble c = new Nybble(); 
    int t;
 
    Console.WriteLine("a: " + (int) a);
    Console.WriteLine("b: " + (int) b);
 
    // use a Nybble in an if statement
    if(a < b) Console.WriteLine("a is less than b\n");
 
    // Add two Nybbles together
    c = a + b;
    Console.WriteLine("c after c = a + b: " + (int) c);
 
    // Add an int to a Nybble
    a += 5;
    Console.WriteLine("a after a += 5: " + (int) a);
 
    Console.WriteLine();
 
    // use a Nybble in an int expression
    t = a * 2 + 3;
    Console.WriteLine("Result of a * 2 + 3: " + t);
    
    Console.WriteLine();
 
    // illustrate int assignment and overflow
    a = 19;
    Console.WriteLine("Result of a = 19: " + (int) a);
    
    Console.WriteLine();
 
    // use a Nybble to control a loop    
    Console.WriteLine("Control a for loop with a Nybble.");
    for(a = 0; a < 10; a++)
      Console.Write((int) a + " ");
 
    Console.WriteLine();
  }
}

listing 1
// Use an indexer to create a fail-soft array.
 
using System;
 
class FailSoftArray { 
  int[] a;    // reference to underlying array 
 
  public int Length; // Length is public
 
  public bool errflag; // indicates outcome of last operation
  
  // Construct array given its size.
  public FailSoftArray(int size) {
    a = new int[size];
    Length = size; 
  }
 
  // This is the indexer for FailSoftArray.
  public int this[int index] {
    // This is the get accessor.
    get {
      if(ok(index)) {
        errflag = false;
        return a[index];
      } else {
        errflag = true;
        return 0;
      }
    }
 
    // This is the set accessor
    set {
      if(ok(index)) {
        a[index] = value;
        errflag = false;
      }
      else errflag = true;
    }
  }
 
  // Return true if index is within bounds.
  private bool ok(int index) {
   if(index >= 0 & index < Length) return true;
   return false;
  }

 
// Demonstrate the fail-soft array.
class FSDemo { 
  public static void Main() { 
    FailSoftArray fs = new FailSoftArray(5);
    int x;
 
    // show quiet failures
    Console.WriteLine("Fail quietly.");
    for(int i=0; i < (fs.Length * 2); i++)
      fs[i] = i*10;
 
    for(int i=0; i < (fs.Length * 2); i++) {
      x = fs[i];
      if(x != -1) Console.Write(x + " ");
    }
    Console.WriteLine();
 
    // now, generate failures
    Console.WriteLine("\nFail with error reports.");
    for(int i=0; i < (fs.Length * 2); i++) {
      fs[i] = i*10;
      if(fs.errflag)
        Console.WriteLine("fs[" + i + "] out-of-bounds");
    }
 
    for(int i=0; i < (fs.Length * 2); i++) {
      x = fs[i];
      if(!fs.errflag) Console.Write(x + " ");
      else
        Console.WriteLine("fs[" + i + "] out-of-bounds");
    }
  }
}

listing 2
// Overload the FailSoftArray indexer.
 
using System; 
 
class FailSoftArray {  
  int[] a;    // reference to underlying array  
 
  public int Length; // Length is public 
 
  public bool errflag; // indicates outcome of last operation 
   
  // Construct array given its size. 
  public FailSoftArray(int size) { 
    a = new int[size]; 
    Length = size;  
  } 
 
  // This is the int indexer for FailSoftArray. 
  public int this[int index] { 
    // This is the get accessor. 
    get { 
      if(ok(index)) { 
        errflag = false; 
        return a[index]; 
      } else { 
        errflag = true; 
        return 0; 
      } 
    } 
 
    // This is the set accessor 
    set { 
      if(ok(index)) { 
        a[index] = value; 
        errflag = false; 
      } 
      else errflag = true; 
    } 
  } 
 
  /* This is another indexer for FailSoftArray.
     This index takes a double argument.  It then
     rounds that argument to the nearest integer
     index. */ 
  public int this[double idx] { 
    // This is the get accessor. 
    get { 
      int index;
 
      // round to nearest int
      if( (idx - (int) idx) < 0.5) index = (int) idx;
      else index = (int) idx + 1;
 
      if(ok(index)) { 
        errflag = false; 
        return a[index]; 
      } else { 
        errflag = true; 
        return 0; 
      } 
    } 
 
    // This is the set accessor 
    set { 
      int index;
 
      // round to nearest int
      if( (idx - (int) idx) < 0.5) index = (int) idx;
      else index = (int) idx + 1;
 
      if(ok(index)) { 
        a[index] = value; 
        errflag = false; 
      } 
      else errflag = true; 
    } 
  } 
 
  // Return true if index is within bounds. 
  private bool ok(int index) { 
   if(index >= 0 & index < Length) return true; 
   return false; 
  } 
}  
  
// Demonstrate the fail-soft array. 
class FSDemo {  
  public static void Main() {  
    FailSoftArray fs = new FailSoftArray(5); 
 
    // put some values in fs
    for(int i=0; i < fs.Length; i++)
      fs[i] = i; 
 
    // now index with ints and doubles
    Console.WriteLine("fs[1]: " + fs[1]);
    Console.WriteLine("fs[2]: " + fs[2]);
 
    Console.WriteLine("fs[1.1]: " + fs[1.1]);
    Console.WriteLine("fs[1.6]: " + fs[1.6]);
 
  } 
}

listing 3
// Indexers don't have to operate on actual arrays.
 
using System;
 
class PwrOfTwo { 
 
  /* Access a logical array that contains
     the powers of 2 from 0 to 15. */
  public int this[int index] {
    // Compute and return power of 2.
    get {
      if((index >= 0) && (index < 16)) return pwr(index);
      else return -1;
    }
 
    // there is no set accessor
  }
 
  int pwr(int p) {
    int result = 1;
 
    for(int i=0; i < p; i++)
      result *= 2;
    
    return result;
  }

 
class UsePwrOfTwo { 
  public static void Main() { 
    PwrOfTwo pwr = new PwrOfTwo();
 
    Console.Write("First 8 powers of 2: ");
    for(int i=0; i < 8; i++)
      Console.Write(pwr[i] + " ");
    Console.WriteLine();
 
    Console.Write("Here are some errors: ");
    Console.Write(pwr[-1] + " " + pwr[17]);
 
    Console.WriteLine();
  }
}

listing 4
// A two-dimensional fail-soft array.
 
using System;
 
class FailSoftArray2D { 
  int[,] a; // reference to underlying 2D array 
  int rows, cols; // dimensions
  public int Length; // Length is public
 
  public bool errflag; // indicates outcome of last operation
  
  // Construct array given its dimensions.
  public FailSoftArray2D(int r, int c) {
    rows = r;
    cols = c;
    a = new int[rows, cols];
    Length = rows * cols; 
  }
 
  // This is the indexer for FailSoftArray2D.
  public int this[int index1, int index2] {
    // This is the get accessor.
    get {
      if(ok(index1, index2)) {
        errflag = false;
        return a[index1, index2];
      } else {
        errflag = true;
        return 0;
      }
    }
 
    // This is the set accessor.
    set {
      if(ok(index1, index2)) {
        a[index1, index2] = value;
        errflag = false;
      }
      else errflag = true;
    }
  }
 
  // Return true if indexes are within bounds.
  private bool ok(int index1, int index2) {
   if(index1 >= 0 & index1 < rows &
      index2 >= 0 & index2 < cols)
         return true;
 
   return false;
  }

 
// Demonstrate a 2D indexer.
class TwoDIndexerDemo { 
  public static void Main() { 
    FailSoftArray2D fs = new FailSoftArray2D(3, 5);
    int x;
 
    // show quiet failures
    Console.WriteLine("Fail quietly.");
    for(int i=0; i < 6; i++)
      fs[i, i] = i*10;
 
    for(int i=0; i < 6; i++) {
      x = fs[i,i];
      if(x != -1) Console.Write(x + " ");
    }
    Console.WriteLine();
 
    // now, generate failures
    Console.WriteLine("\nFail with error reports.");
    for(int i=0; i < 6; i++) {
      fs[i,i] = i*10;
      if(fs.errflag)
        Console.WriteLine("fs[" + i + ", " + i + "] out-of-bounds");
    }
 
    for(int i=0; i < 6; i++) {
      x = fs[i,i];
      if(!fs.errflag) Console.Write(x + " ");
      else
        Console.WriteLine("fs[" + i + ", " + i + "] out-of-bounds");
    }
  }
}

listing 5
// A simple property example.
 
using System;
 
class SimpProp { 
  int prop; // field being managed by MyProp
 
  public SimpProp() { prop = 0; }
 
  /* This is the property that supports access to
     the private instance variable prop.  It
     allows only positive values. */
  public int MyProp {
    get {
      return prop;
    }
    set {
      if(value >= 0) prop = value;
    } 
  }

 
// Demonstrate a property.
class PropertyDemo { 
  public static void Main() { 
    SimpProp ob = new SimpProp();
 
    Console.WriteLine("Original value of ob.MyProp: " + ob.MyProp);
 
    ob.MyProp = 100; // assign value
    Console.WriteLine("Value of ob.MyProp: " + ob.MyProp);
 
    // Can't assign negative value to prop
    Console.WriteLine("Attempting to assign -10 to ob.MyProp");
    ob.MyProp = -10;
    Console.WriteLine("Value of ob.MyProp: " + ob.MyProp);
  }
}

listing 6
// Add Length property to FailSoftArray.
 
using System;
 
class FailSoftArray { 
  int[] a; // reference to underlying array 
  int len; // length of array -- underlies Length property
 
  public bool errflag; // indicates outcome of last operation
  
  // Construct array given its size. 
  public FailSoftArray(int size) {
    a = new int[size];
    len = size; 
  }
 
  // Read-only Length property.
  public int Length {
    get {
      return len;
    }
  }
 
  // This is the indexer for FailSoftArray.
  public int this[int index] {
    // This is the get accessor.
    get {
      if(ok(index)) {
        errflag = false;
        return a[index];
      } else {
        errflag = true;
        return 0;
      }
    }
 
    // This is the set accessor
    set {
      if(ok(index)) {
        a[index] = value;
        errflag = false;
      }
      else errflag = true;
    }
  }
 
  // Return true if index is within bounds.
  private bool ok(int index) {
   if(index >= 0 & index < Length) return true;
   return false;
  }

 
// Demonstrate the improved fail-soft array.
class ImprovedFSDemo { 
  public static void Main() { 
    FailSoftArray fs = new FailSoftArray(5);
    int x;
 
    // can read Length
    for(int i=0; i < fs.Length; i++)
      fs[i] = i*10;
 
    for(int i=0; i < fs.Length; i++) {
      x = fs[i];
      if(x != -1) Console.Write(x + " ");
    }
    Console.WriteLine();
 
    // fs.Length = 10; // Error, illegal!
  }
}

listing 7
// Convert errflag into a property.
 
using System;
 
class FailSoftArray { 
  int[] a; // reference to underlying array 
  int len; // length of array
 
  bool errflag; // now private
  
  // Construct array given its size. 
  public FailSoftArray(int size) {
    a = new int[size];
    len = size; 
  }
 
  // Read-only Length property.
  public int Length {
    get {
      return len;
    }
  }
 
  // Read-only Error property.
  public bool Error {
    get {
      return errflag;
    }
  }
 
  // This is the indexer for FailSoftArray.
  public int this[int index] {
    // This is the get accessor.
    get {
      if(ok(index)) {
        errflag = false;
        return a[index];
      } else {
        errflag = true;
        return 0;
      }
    }
 
    // This is the set accessor
    set {
      if(ok(index)) {
        a[index] = value;
        errflag = false;
      }
      else errflag = true;
    }
  }
 
  // Return true if index is within bounds.
  private bool ok(int index) {
   if(index >= 0 & index < Length) return true;
   return false;
  }

 
// Demonstrate the improved fail-soft array.
class FinalFSDemo { 
  public static void Main() { 
    FailSoftArray fs = new FailSoftArray(5);
 
    // use Error property
    for(int i=0; i < fs.Length + 1; i++) {
      fs[i] = i*10;
      if(fs.Error) 
        Console.WriteLine("Error with index " + i);
    }
 
  }
}

listing 8
// Use an access modifier with an accessor.
 
using System; 
 
class PropAccess {  
  int prop; // field being managed by MyProp 
 
  public PropAccess() { prop = 0; } 
 
  /* This is the property that supports access to 
     the private instance variable prop.  It allows
     any code to obtain the value of prop, but
     only other class members can set the value
     of prop. */ 
  public int MyProp { 
    get { 
      return prop; 
    } 
    private set { // now, private 
      prop = value; 
    }  
  } 
 
  // This class member increments the value of MyProp.
  public void incrProp() {
    MyProp++; // OK, in same class.
  }
}  
 
// Demonstrate accessor access modifier.
class PropAccessDemo {  
  public static void Main() {  
    PropAccess ob = new PropAccess(); 
 
    Console.WriteLine("Original value of ob.MyProp: " + ob.MyProp); 
 
//    ob.MyProp = 100; // can't access set
 
    ob.incrProp();
    Console.WriteLine("Value of ob.MyProp after increment: "
                      + ob.MyProp); 
  } 
}

listing 9
/* Create a specifiable range array class.
   The RangeArray class allows indexing
   to begin at some value other than zero.
   When you create a RangeArray, you specify
   the beginning and ending index. Negative
   indexes are also  allowed.  For example,
   you can create arrays that index from -5 to 5, 
   1 to 10, or 50 to 56.
*/
 
using System; 
 
class RangeArray {  
  // private data
  int[] a; // reference to underlying array  
  int lowerBound; // lowest index
  int upperBound; // greatest index
 
  // data for properties
  int len; // underlying var for Length property
  bool errflag; // underlying var for outcome 
   
  // Construct array given its size. 
  public RangeArray(int low, int high) { 
    high++;
    if(high <= low) {
      Console.WriteLine("Invalid Indices");
      high = 1; // create a minimal array for safety
      low = 0;
    }
    a = new int[high - low]; 
    len = high - low;  
 
    lowerBound = low;
    upperBound = --high;
  } 
 
  // Read-only Length property. 
  public int Length { 
    get { 
      return len; 
    } 
  } 
 
  // Read-only Error property. 
  public bool Error { 
    get { 
      return errflag; 
    } 
  } 
 
  // This is the indexer for RangeArray. 
  public int this[int index] { 
    // This is the get accessor. 
    get { 
      if(ok(index)) { 
        errflag = false; 
        return a[index - lowerBound]; 
      } else { 
        errflag = true; 
        return 0; 
      } 
    } 
 
    // This is the set accessor 
    set { 
      if(ok(index)) { 
        a[index - lowerBound] = value; 
        errflag = false; 
      } 
      else errflag = true; 
    } 
  } 
 
  // Return true if index is within bounds. 
  private bool ok(int index) { 
    if(index >= lowerBound & index <= upperBound) return true; 
    return false; 
  } 
}  
  
// Demonstrate the index-range array. 
class RangeArrayDemo {  
  public static void Main() {  
    RangeArray ra = new RangeArray(-5, 5); 
    RangeArray ra2 = new RangeArray(1, 10); 
    RangeArray ra3 = new RangeArray(-20, -12); 
 
    // Demonstrate ra
    Console.WriteLine("Length of ra: " + ra.Length);
 
    for(int i = -5; i <= 5; i++)
      ra[i] = i;
  
    Console.Write("Contents of ra: ");
    for(int i = -5; i <= 5; i++)
      Console.Write(ra[i] + " ");
 
    Console.WriteLine("\n");
 
    // Demonstrate ra2
    Console.WriteLine("Length of ra2: " + ra2.Length);
 
    for(int i = 1; i <= 10; i++)
      ra2[i] = i;
 
    Console.Write("Contents of ra2: ");
    for(int i = 1; i <= 10; i++)
      Console.Write(ra2[i] + " ");
 
    Console.WriteLine("\n");
 
    // Demonstrate ra3
    Console.WriteLine("Length of ra3: " + ra3.Length);
 
    for(int i = -20; i <= -12; i++)
      ra3[i] = i;
 
    Console.Write("Contents of ra3: ");
    for(int i = -20; i <= -12; i++)
      Console.Write(ra3[i] + " ");
 
    Console.WriteLine("\n");
 
  } 
}

listing 1
// A simple class hierarchy.
 
using System;
 
// A class for two-dimensional objects.
class TwoDShape {
  public double width;
  public double height;
 
  public void showDim() {
    Console.WriteLine("Width and height are " +
                       width + " and " + height);
  }
}
 
// Triangle is derived from TwoDShape.
class Triangle : TwoDShape {
  public string style; // style of triangle
  
  // Return area of triangle.
  public double area() {
    return width * height / 2;
  }
 
  // Display a triangle's style.
  public void showStyle() {
    Console.WriteLine("Triangle is " + style);
  }
}
 
class Shapes {
  public static void Main() {
    Triangle t1 = new Triangle();
    Triangle t2 = new Triangle();
 
    t1.width = 4.0;
    t1.height = 4.0;
    t1.style = "isosceles";
 
    t2.width = 8.0;
    t2.height = 12.0;
    t2.style = "right";
 
    Console.WriteLine("Info for t1: ");
    t1.showStyle();
    t1.showDim();
    Console.WriteLine("Area is " + t1.area());
 
    Console.WriteLine();
 
    Console.WriteLine("Info for t2: ");
    t2.showStyle();
    t2.showDim();
    Console.WriteLine("Area is " + t2.area());
  }
}

listing 2
// Private members are not inherited. 
 
// This example will not compile.
using System;
 
// A class for two-dimensional objects.
class TwoDShape {
  double width;  // now private
  double height; // now private
 
  public void showDim() {
    Console.WriteLine("Width and height are " +
                       width + " and " + height);
  }
}
 
// Triangle is derived from TwoDShape.
class Triangle : TwoDShape {
  public string style; // style of triangle
  
  // Return area of triangle.
  public double area() {
    return width * height / 2; // Error, can't access private member
  }
 
  // Display a triangle's style.
  public void showStyle() {
    Console.WriteLine("Triangle is " + style);
  }
}

listing 3
// Use properties to set and get private members.
 
using System;
 
// A class for two-dimensional objects.
class TwoDShape {
  double pri_width;  // now private
  double pri_height; // now private 
 
  // Properties for width and height.
  public double width {
     get { return pri_width; }
     set { pri_width = value; }
  }
 
  public double height {
     get { return pri_height; }
     set { pri_height = value; }
  }
 
  public void showDim() {
    Console.WriteLine("Width and height are " +
                       width + " and " + height);
  }
}
 
// A derived class of TwoDShape for triangles.
class Triangle : TwoDShape {
  public string style; // style of triangle
  
  // Return area of triangle.
  public double area() {
    return width * height / 2; 
  }
 
  // Display a triangle's style.
  public void showStyle() {
    Console.WriteLine("Triangle is " + style);
  }
}
 
class Shapes2 {
  public static void Main() {
    Triangle t1 = new Triangle();
    Triangle t2 = new Triangle();
 
    t1.width = 4.0;
    t1.height = 4.0;
    t1.style = "isosceles";
 
    t2.width = 8.0;
    t2.height = 12.0;
    t2.style = "right";
 
    Console.WriteLine("Info for t1: ");
    t1.showStyle();
    t1.showDim();
    Console.WriteLine("Area is " + t1.area());
 
    Console.WriteLine();
 
    Console.WriteLine("Info for t2: ");
    t2.showStyle();
    t2.showDim();
    Console.WriteLine("Area is " + t2.area());
  }
}

listing 4
// Demonstrate protected.
 
using System;
 
class B {
  protected int i, j; // private to B, but accessible by D
 
  public void set(int a, int b) {
    i = a;
    j = b;
  }
 
  public void show() {
    Console.WriteLine(i + " " + j);
 }
}
 
class D : B {
  int k; // private
 
  // D can access B's i and j
  public void setk() {
     k = i * j;
  }
 
  public void showk() {
    Console.WriteLine(k);
  }
}
 
class ProtectedDemo {
  public static void Main() {
    D ob = new D();
 
    ob.set(2, 3); // OK, known to D
    ob.show();    // OK, known to D
 
    ob.setk();  // OK, part of D
    ob.showk(); // OK, part of D
  }
}

listing 5
// Add a constructor to Triangle.
 
using System;
 
// A class for two-dimensional objects.
class TwoDShape {
  double pri_width;  // private
  double pri_height; // private 
 
  // properties for width and height.
  public double width {
     get { return pri_width; }
     set { pri_width = value; }
  }
 
  public double height {
     get { return pri_height; }
     set { pri_height = value; }
  }
 
  public void showDim() {
    Console.WriteLine("Width and height are " +
                       width + " and " + height);
  }
}
 
// A derived class of TwoDShape for triangles.
class Triangle : TwoDShape {
  string style; // private
  
  // Constructor
  public Triangle(string s, double w, double h) {
    width = w;  // init the base class
    height = h; // init the base class
 
    style = s;  // init the derived class
  }
 
  // Return area of triangle.
  public double area() {
    return width * height / 2; 
  }
 
  // Display a triangle's style.
  public void showStyle() {
    Console.WriteLine("Triangle is " + style);
  }
}
 
class Shapes3 {
  public static void Main() {
    Triangle t1 = new Triangle("isosceles", 4.0, 4.0);
    Triangle t2 = new Triangle("right", 8.0, 12.0);
 
    Console.WriteLine("Info for t1: ");
    t1.showStyle();
    t1.showDim();
    Console.WriteLine("Area is " + t1.area());
 
    Console.WriteLine();
 
    Console.WriteLine("Info for t2: ");
    t2.showStyle();
    t2.showDim();
    Console.WriteLine("Area is " + t2.area());
  }
}

listing 6
// Add constructors to TwoDShape.
 
using System;
 
// A class for two-dimensional objects.
class TwoDShape {
  double pri_width;  // private
  double pri_height; // private 
 
  // Constructor for TwoDShape.
  public TwoDShape(double w, double h) {
    width = w;
    height = h;
  }
 
  // properties for width and height.
  public double width {
     get { return pri_width; }
     set { pri_width = value; }
  }
 
  public double height {
     get { return pri_height; }
     set { pri_height = value; }
  }
 
  public void showDim() {
    Console.WriteLine("Width and height are " +
                       width + " and " + height);
  }
}
 
 // A derived class of TwoDShape for triangles.
class Triangle : TwoDShape {
  string style; // private
  
  // Call the base class constructor.
  public Triangle(string s, double w, double h) : base(w, h) {
    style = s; 
  }
 
  // Return area of triangle.
  public double area() {
    return width * height / 2;
  }
 
  // Display a triangle's style.
  public void showStyle() {
    Console.WriteLine("Triangle is " + style);
  }
}
 
class Shapes4 {
  public static void Main() {
    Triangle t1 = new Triangle("isosceles", 4.0, 4.0);
    Triangle t2 = new Triangle("right", 8.0, 12.0);
 
    Console.WriteLine("Info for t1: ");
    t1.showStyle();
    t1.showDim();
    Console.WriteLine("Area is " + t1.area());
 
    Console.WriteLine();
 
    Console.WriteLine("Info for t2: ");
    t2.showStyle();
    t2.showDim();
    Console.WriteLine("Area is " + t2.area());
  }
}

listing 7
// Add more constructors to TwoDShape.
 
using System;
 
class TwoDShape {
  double pri_width;  // private
  double pri_height; // private 
 
  // Default constructor.
  public TwoDShape() {
    width = height = 0.0;
  }
 
  // Constructor for TwoDShape.
  public TwoDShape(double w, double h) {
    width = w;
    height = h;
  }
 
  // Construct object with equal width and height.
  public TwoDShape(double x) {
    width = height = x;
  }
 
  // Properties for width and height.
  public double width {
     get { return pri_width; }
     set { pri_width = value; }
  }
 
  public double height {
     get { return pri_height; }
     set { pri_height = value; }
  }
 
  public void showDim() {
    Console.WriteLine("Width and height are " +
                       width + " and " + height);
  }
}
 
// A derived class of TwoDShape for triangles.
class Triangle : TwoDShape {
  string style; // private
  
  /* A default constructor. This automatically invokes
     the default constructor of TwoDShape. */
  public Triangle() {
    style = "null";
  }
 
  // Constructor that takes three arguments.
  public Triangle(string s, double w, double h) : base(w, h) {
    style = s; 
  }
 
  // Construct an isosceles triangle.
  public Triangle(double x) : base(x) {
    style = "isosceles"; 
  }
 
  // Return area of triangle.
  public double area() {
    return width * height / 2;
  }
 
  // Display a triangle's style.
  public void showStyle() {
    Console.WriteLine("Triangle is " + style);
  }
}
 
class Shapes5 {
  public static void Main() {
    Triangle t1 = new Triangle();
    Triangle t2 = new Triangle("right", 8.0, 12.0);
    Triangle t3 = new Triangle(4.0);
 
    t1 = t2;
 
    Console.WriteLine("Info for t1: ");
    t1.showStyle();
    t1.showDim();
    Console.WriteLine("Area is " + t1.area());
 
    Console.WriteLine();
 
    Console.WriteLine("Info for t2: ");
    t2.showStyle();
    t2.showDim();
    Console.WriteLine("Area is " + t2.area());
 
    Console.WriteLine();
 
    Console.WriteLine("Info for t3: ");
    t3.showStyle();
    t3.showDim();
    Console.WriteLine("Area is " + t3.area());
 
    Console.WriteLine();
  }
}

listing 8
// An example of inheritance-related name hiding.
 
using System;
 
class A {
  public int i = 0;
}
 
// Create a derived class.
class B : A {
  new int i; // this i hides the i in A
 
  public B(int b) {
    i = b; // i in B
  }
 
  public void show() {
    Console.WriteLine("i in derived class: " + i);
  }
}
 
class NameHiding {
  public static void Main() {
    B ob = new B(2);
 
    ob.show();
  }
}

listing 9
// Using base to overcome name hiding.
 
using System;
 
class A {
  public int i = 0;
}
 
// Create a derived class.
class B : A {
  new int i; // this i hides the i in A
 
  public B(int a, int b) {
    base.i = a; // this uncovers the i in A
    i = b; // i in B
  }
 
  public void show() {
    // this displays the i in A.
    Console.WriteLine("i in base class: " + base.i);
 
    // this displays the i in B
    Console.WriteLine("i in derived class: " + i);
  }
}
 
class UncoverName {
  public static void Main() {
    B ob = new B(1, 2);
 
    ob.show();
  }
}

listing 10
// Call a hidden method.
 
using System;
 
class A {
  public int i = 0;
 
  // show() in A
  public void show() {
    Console.WriteLine("i in base class: " + i);
  }
}
 
// Create a derived class.
class B : A {
  new int i; // this i hides the i in A
 
  public B(int a, int b) {
    base.i = a; // this uncovers the i in A
    i = b; // i in B
  }

  // This hides show() in A. Notice the use of new.
  new public void show() {
    base.show(); // this calls show() in A
 
    // this displays the i in B
    Console.WriteLine("i in derived class: " + i);
  }
}
 
class UncoverName {
  public static void Main() {
    B ob = new B(1, 2);
 
    ob.show();
  }
}

listing 11
// A multilevel hierarchy.
 
using System;
 
class TwoDShape {
  double pri_width;  // private
  double pri_height; // private 
 
  // Default constructor.
  public TwoDShape() {
    width = height = 0.0;
  }
 
  // Constructor for TwoDShape.
  public TwoDShape(double w, double h) {
    width = w;
    height = h;
  }
 
  // Construct object with equal width and height.
  public TwoDShape(double x) {
    width = height = x;
  }
 
  // Properties for width and height.
  public double width {
     get { return pri_width; }
     set { pri_width = value; }
  }
 
  public double height {
     get { return pri_height; }
     set { pri_height = value; }
  }
 
  public void showDim() {
    Console.WriteLine("Width and height are " +
                       width + " and " + height);
  }
}
 
// A derived class of TwoDShape for triangles.
class Triangle : TwoDShape {
  string style; // private
  
  /* A default constructor. This invokes the default
     constructor of TwoDShape. */
  public Triangle() {
    style = "null";
  }
 
  // Constructor
  public Triangle(string s, double w, double h) : base(w, h) {
    style = s; 
  }
 
  // Construct an isosceles triangle.
  public Triangle(double x) : base(x) {
    style = "isosceles"; 
  }
 
  // Return area of triangle.
  public double area() {
    return width * height / 2;
  }
 
  // Display a triangle's style.
  public void showStyle() {
    Console.WriteLine("Triangle is " + style);
  }
}
 
// Extend Triangle.
class ColorTriangle : Triangle {
  string color;
 
  public ColorTriangle(string c, string s,
                       double w, double h) : base(s, w, h) {
    color = c;
  }
 
  // Display the color.
  public void showColor() {
    Console.WriteLine("Color is " + color);
  }
}
 
class Shapes6 {
  public static void Main() {
    ColorTriangle t1 = 
         new ColorTriangle("Blue", "right", 8.0, 12.0);
    ColorTriangle t2 = 
         new ColorTriangle("Red", "isosceles", 2.0, 2.0);
 
    Console.WriteLine("Info for t1: ");
    t1.showStyle();
    t1.showDim();
    t1.showColor();
    Console.WriteLine("Area is " + t1.area());
 
    Console.WriteLine();
 
    Console.WriteLine("Info for t2: ");
    t2.showStyle();
    t2.showDim();
    t2.showColor();
    Console.WriteLine("Area is " + t2.area());
  }
}

listing 12
// Demonstrate when constructors are called.
 
using System;
 
// Create a base class.
class A {
  public A() { 
    Console.WriteLine("Constructing A.");
  }
}
 
// Create a class derived from A.
class B : A {
  public B() {
    Console.WriteLine("Constructing B.");
  }
}
 
// Create a class derived from B.
class C : B {
  public C() {
    Console.WriteLine("Constructing C.");
  }
}
 
class OrderOfConstruction {
  public static void Main() {
    C c = new C();
  }
}

listing 13
// This program will not compile.
 
class X {
  int a;
 
  public X(int i) { a = i; }
}
 
class Y {
  int a;
 
  public Y(int i) { a = i; }
}
 
class IncompatibleRef {
  public static void Main() {
    X x = new X(10);
    X x2; 
    Y y = new Y(5);
 
    x2 = x; // OK, both of same type
 
    x2 = y; // Error, not of same type
  }
}

listing 14
// A base class reference can refer to a derived class object.
 
using System;
 
class X {
  public int a;
 
  public X(int i) {
    a = i;
  }
}
 
class Y : X {
  public int b;
 
  public Y(int i, int j) : base(j) {
    b = i;
  }
}
 
class BaseRef {
  public static void Main() {
    X x = new X(10);
    X x2; 
    Y y = new Y(5, 6);
 
    x2 = x; // OK, both of same type
    Console.WriteLine("x2.a: " + x2.a);
 
    x2 = y; // Ok because Y is derived from X
    Console.WriteLine("x2.a: " + x2.a);
 
    // X references know only about X members
    x2.a = 19; // OK
//    x2.b = 27; // Error, X doesn't have a b member
  }
}

listing 15
// Pass a derived class reference to a base class reference.
 
using System;
 
class TwoDShape {
  double pri_width;  // private
  double pri_height; // private
 
  // Default constructor.
  public TwoDShape() {
    width = height = 0.0;
  }
 
  // Constructor for TwoDShape.
  public TwoDShape(double w, double h) {
    width = w;
    height = h;
  }
 
  // Construct object with equal width and height.
  public TwoDShape(double x) {
    width = height = x;
  }
 
  // Construct object from an object.
  public TwoDShape(TwoDShape ob) {
    width = ob.width;
    height = ob.height;
  }
 
  // Properties for width and height.
  public double width {
     get { return pri_width; }
     set { pri_width = value; }
  }
 
  public double height {
     get { return pri_height; }
     set { pri_height = value; }
  }
 
  public void showDim() {
    Console.WriteLine("Width and height are " +
                       width + " and " + height);
  }
}
 
// A derived class of TwoDShape for triangles.
class Triangle : TwoDShape {
  string style; // private
  
  // A default constructor.
  public Triangle() {
    style = "null";
  }
 
  // Constructor for Triangle.
  public Triangle(string s, double w, double h) : base(w, h) {
    style = s; 
  }
 
  // Construct an isosceles triangle.
  public Triangle(double x) : base(x) {
    style = "isosceles"; 
  }
 
  // Construct an object from an object.
  public Triangle(Triangle ob) : base(ob) {
    style = ob.style;
  }
 
  // Return area of triangle.
  public double area() {
    return width * height / 2;
  }
 
  // Display a triangle's style.
  public void showStyle() {
    Console.WriteLine("Triangle is " + style);
  }
}
 
class Shapes7 {
  public static void Main() {
    Triangle t1 = new Triangle("right", 8.0, 12.0);
 
    // make a copy of t1
    Triangle t2 = new Triangle(t1);
 
    Console.WriteLine("Info for t1: ");
    t1.showStyle();
    t1.showDim();
    Console.WriteLine("Area is " + t1.area());
 
    Console.WriteLine();
 
    Console.WriteLine("Info for t2: ");
    t2.showStyle();
    t2.showDim();
    Console.WriteLine("Area is " + t2.area());
  }
}

listing 16
// Demonstrate a virtual method.
 
using System;
 
class Base {
  // Create virtual method in the base class. 
  public virtual void who() {
    Console.WriteLine("who() in Base");
  }
}
 
class Derived1 : Base {
  // Override who() in a derived class.
  public override void who() {
    Console.WriteLine("who() in Derived1");
  }
}
 
class Derived2 : Base {
  // Override who() again in another derived class.
  public override void who() {
    Console.WriteLine("who() in Derived2");
  }
}
 
class OverrideDemo {
  public static void Main() {
    Base baseOb = new Base();
    Derived1 dOb1 = new Derived1();
    Derived2 dOb2 = new Derived2();
 
    Base baseRef; // a base-class reference
 
    baseRef = baseOb; 
    baseRef.who();
 
    baseRef = dOb1; 
    baseRef.who();
 
    baseRef = dOb2; 
    baseRef.who();
  }
}

listing 17
/* When a virtual method is not overridden,
   the base class method is used. */
 
using System;
 
class Base {
  // Create virtual method in the base class. 
  public virtual void who() {
    Console.WriteLine("who() in Base");
  }
}
 
class Derived1 : Base {
  // Override who() in a derived class.
  public override void who() {
    Console.WriteLine("who() in Derived1");
  }
}
 
class Derived2 : Base {
  // This class does not override who().
}
 
class NoOverrideDemo {
  public static void Main() {
    Base baseOb = new Base();
    Derived1 dOb1 = new Derived1();
    Derived2 dOb2 = new Derived2();
 
    Base baseRef; // a base-class reference
 
    baseRef = baseOb; 
    baseRef.who();
 
    baseRef = dOb1; 
    baseRef.who();
 
    baseRef = dOb2; 
    baseRef.who(); // calls Base's who()
  }
}

listing 18
/*  In a multilevel hierarchy, the 
    first override of a virtual method
    that is found while moving up the
    hierarchy is the one executed. */
 
using System; 
 
class Base { 
  // Create virtual method in the base class.  
  public virtual void who() { 
    Console.WriteLine("who() in Base"); 
  } 

 
class Derived1 : Base { 
  // Override who() in a derived class. 
  public override void who() { 
    Console.WriteLine("who() in Derived1"); 
  } 

 
class Derived2 : Derived1 { 
  // This class also does not override who(). 

 
class Derived3 : Derived2 { 
  // This class does not override who(). 

 
class NoOverrideDemo2 { 
  public static void Main() { 
    Derived3 dOb = new Derived3(); 
    Base baseRef; // a base-class reference 
 
    baseRef = dOb;  
    baseRef.who(); // calls Derived1's who() 
  } 
}

listing 19
// Use virtual methods and polymorphism.
 
using System;
 
class TwoDShape { 
  double pri_width;  // private
  double pri_height; // private
  string pri_name;   // private
 
  // A default constructor. 
  public TwoDShape() { 
    width = height = 0.0; 
    name = "null"; 
  } 
 
  // Parameterized constructor. 
  public TwoDShape(double w, double h, string n) { 
    width = w; 
    height = h; 
    name = n; 
  } 
 
  // Construct object with equal width and height. 
  public TwoDShape(double x, string n) { 
    width = height = x; 
    name = n; 
  } 
 
  // Construct an object from an object. 
  public TwoDShape(TwoDShape ob) { 
    width = ob.width; 
    height = ob.height; 
    name = ob.name; 
  } 
 
  // Properties for width, height, and name
  public double width {
    get { return pri_width; }
    set { pri_width = value; }
  }
 
  public double height {
    get { return pri_height; }
    set { pri_height = value; }
  }
 
  public string name {
    get { return pri_name; }
    set { pri_name = value; }
  }
 
  public void showDim() { 
    Console.WriteLine("Width and height are " + 
                       width + " and " + height); 
  } 
 
  public virtual double area() {  
    Console.WriteLine("area() must be overridden"); 
    return 0.0; 
  }  

 
// A derived class of TwoDShape for triangles.
class Triangle : TwoDShape { 
  string style; // private
   
  // A default constructor. 
  public Triangle() { 
    style = "null"; 
  } 
 
  // Constructor for Triangle. 
  public Triangle(string s, double w, double h) :
    base(w, h, "triangle") { 
      style = s;  
  } 
 
  // Construct an isosceles triangle. 
  public Triangle(double x) : base(x, "triangle") { 
    style = "isosceles";  
  } 
 
  // Construct an object from an object. 
  public Triangle(Triangle ob) : base(ob) { 
    style = ob.style; 
  } 
 
  // Override area() for Triangle.
  public override double area() { 
    return width * height / 2; 
  } 
 
  // Display a triangle's style.
  public void showStyle() { 
    Console.WriteLine("Triangle is " + style); 
  } 

 
// A derived class of TwoDShape for rectangles.  
class Rectangle : TwoDShape {  
  // Constructor for Rectangle. 
  public Rectangle(double w, double h) : 
    base(w, h, "rectangle"){ } 
 
  // Construct a square. 
  public Rectangle(double x) : 
    base(x, "rectangle") { } 
 
  // Construct an object from an object. 
  public Rectangle(Rectangle ob) : base(ob) { } 
 
  // Return true if the rectangle is square.
  public bool isSquare() {  
    if(width == height) return true;  
    return false;  
  }  
    
  // Override area() for Rectangle.
  public override double area() {  
    return width * height;  
  }  

 
class DynShapes { 
  public static void Main() { 
    TwoDShape[] shapes = new TwoDShape[5]; 
 
    shapes[0] = new Triangle("right", 8.0, 12.0); 
    shapes[1] = new Rectangle(10); 
    shapes[2] = new Rectangle(10, 4); 
    shapes[3] = new Triangle(7.0); 
    shapes[4] = new TwoDShape(10, 20, "generic");
 
    for(int i=0; i < shapes.Length; i++) { 
      Console.WriteLine("object is " + shapes[i].name); 
      Console.WriteLine("Area is " + shapes[i].area()); 
 
      Console.WriteLine();   
    } 
  } 
}

listing 20
// Create an abstract class.
 
using System;
 
abstract class TwoDShape { 
  double pri_width;  // private
  double pri_height; // private
  string pri_name;   // private
 
  // A default constructor. 
  public TwoDShape() { 
    width = height = 0.0; 
    name = "null"; 
  } 
 
  // Parameterized constructor. 
  public TwoDShape(double w, double h, string n) { 
    width = w; 
    height = h; 
    name = n; 
  } 
 
  // Construct object with equal width and height. 
  public TwoDShape(double x, string n) { 
    width = height = x; 
    name = n; 
  } 
 
  // Construct an object from an object. 
  public TwoDShape(TwoDShape ob) { 
    width = ob.width; 
    height = ob.height; 
    name = ob.name; 
  } 
 
  // Properties for width, height, and name
  public double width {
    get { return pri_width; }
    set { pri_width = value; }
  }
 
  public double height {
    get { return pri_height; }
    set { pri_height = value; }
  }
 
  public string name {
    get { return pri_name; }
    set { pri_name = value; }
  }
 
  public void showDim() { 
    Console.WriteLine("Width and height are " + 
                       width + " and " + height); 
  } 
 
  // Now, area() is abstract.
  public abstract double area();

 
// A derived class of TwoDShape for triangles.
class Triangle : TwoDShape { 
  string style; // private
   
  // A default constructor. 
  public Triangle() { 
    style = "null"; 
  } 
 
  // Constructor for Triangle. 
  public Triangle(string s, double w, double h) :
    base(w, h, "triangle") { 
      style = s;  
  } 
 
  // Construct an isosceles triangle. 
  public Triangle(double x) : base(x, "triangle") { 
    style = "isosceles";  
  } 
 
  // Construct an object from an object. 
  public Triangle(Triangle ob) : base(ob) { 
    style = ob.style; 
  } 
 
  // Override area() for Triangle.
  public override double area() { 
    return width * height / 2; 
  } 
 
  // Display a triangle's style.
  public void showStyle() { 
    Console.WriteLine("Triangle is " + style); 
  } 

 
// A derived class of TwoDShape for rectangles.  
class Rectangle : TwoDShape {  
  // Constructor for Rectangle. 
  public Rectangle(double w, double h) : 
    base(w, h, "rectangle"){ } 
 
  // Construct a square. 
  public Rectangle(double x) : 
    base(x, "rectangle") { } 
 
  // Construct an object from an object. 
  public Rectangle(Rectangle ob) : base(ob) { } 
 
  // Return true if the rectangle is square.
  public bool isSquare() {  
    if(width == height) return true;  
    return false;  
  }  
    
  // Override area() for Rectangle.
  public override double area() {  
    return width * height;  
  }  

 
class AbsShape { 
  public static void Main() { 
    TwoDShape[] shapes = new TwoDShape[4]; 
 
    shapes[0] = new Triangle("right", 8.0, 12.0); 
    shapes[1] = new Rectangle(10); 
    shapes[2] = new Rectangle(10, 4); 
    shapes[3] = new Triangle(7.0); 
 
    for(int i=0; i < shapes.Length; i++) { 
      Console.WriteLine("object is " + shapes[i].name); 
      Console.WriteLine("Area is " + shapes[i].area()); 
 
      Console.WriteLine();   
    } 
  } 
}

listing 21
// Demonstrate ToString()
 
using System;
 
class MyClass {
  static int count = 0;
  int id;
 
  public MyClass() {
    id = count;
    count++;
  }
 
  public override string ToString() {
    return "MyClass object #" + id;
  }
}
 
class Test {
  public static void Main() {
    MyClass ob1 = new MyClass();
    MyClass ob2 = new MyClass();
    MyClass ob3 = new MyClass();
 
    Console.WriteLine(ob1);
    Console.WriteLine(ob2);
    Console.WriteLine(ob3);
 
  }
}

listing 22
// A simple boxing/unboxing example.
 
using System;
 
class BoxingDemo {
  public static void Main() {
    int x;
    object obj;
 
    x = 10;
    obj = x; // box x into an object
 
    int y = (int)obj; // unbox obj into an int
    Console.WriteLine(y);
  }
}

listing 23
// Boxing also occurs when passing values.
 
using System;
 
class BoxingDemo {
  public static void Main() {
    int x;
   
    x = 10;
    Console.WriteLine("Here is x: " + x);
 
    // x is automatically boxed when passed to sqr()
    x = BoxingDemo.sqr(x);
    Console.WriteLine("Here is x squared: " + x);
  }
 
  static int sqr(object o) {
    return (int)o * (int)o;
  }
}

listing 24
// Boxing makes it possible to call methods on a value!
 
using System;
 
class MethOnValue {
  public static void Main() {
 
    Console.WriteLine(10.ToString());
 
  }
}

listing 25
// Use object to create a generic array.
 
using System;
 
class GenericDemo {  
  public static void Main() {  
    object[] ga = new object[10];
 
    // store ints
    for(int i=0; i < 3; i++)
      ga[i] = i;
 
    // store doubles
    for(int i=3; i < 6; i++)
      ga[i] = (double) i / 2; 
 
 
    // store two strings, a bool, and a char
    ga[6] = "Generic Array";
    ga[7] = true;
    ga[8] = 'X';
    ga[9] = "end";
 
    for(int i = 0; i < ga.Length; i++)
      Console.WriteLine("ga[" + i + "]: " + ga[i] + " ");
 
  } 
}

listing 1
public interface ISeries {
  int getNext(); // return next number in series
  void reset(); // restart
  void setStart(int x); // set starting value
}

listing 2
// Implement ISeries.
class ByTwos : ISeries {
  int start;
  int val;
 
  public ByTwos() {
    start = 0;
    val = 0;
  } 
 
  public int getNext() {
    val += 2;
    return val;
  }
 
  public void reset() {
    val = start;
  }
 
  public void setStart(int x) {
    start = x;
    val = start;
  }
}

listing 3
// Demonstrate the ByTwos interface.
 
using System;
 
class SeriesDemo {
  public static void Main() {
    ByTwos ob = new ByTwos();
 
    for(int i=0; i < 5; i++)
      Console.WriteLine("Next value is " +
                         ob.getNext());
 
    Console.WriteLine("\nResetting");
    ob.reset();
    for(int i=0; i < 5; i++)
      Console.WriteLine("Next value is " +
                         ob.getNext());
 
    Console.WriteLine("\nStarting at 100");
    ob.setStart(100);
    for(int i=0; i < 5; i++)
      Console.WriteLine("Next value is " +
                         ob.getNext());
  }
}

listing 4
// Implement ISeries and add getPrevious().
 class ByTwos : ISeries {
  int start;
  int val;
  int prev;
 
  public ByTwos() {
    start = 0;
    val = 0;
    prev = -2;
  } 
 
  public int getNext() {
    prev = val;
    val += 2;
    return val;
  }
 
  public void reset() {
    val = start;
    prev = start - 2;
  }
 
  public void setStart(int x) {
    start = x;
    val = start;
    prev = val - 2;
  }
 
  // A method not specified by ISeries.
  public int getPrevious() {
    return prev;
  }
}

listing 5
// Use ISeries to implement a series of prime numbers. 
class Primes : ISeries { 
  int start; 
  int val; 
 
  public Primes() { 
    start = 2; 
    val = 2; 
  }  
 
  public int getNext() { 
    int i, j;
    bool isprime;
 
    val++;
    for(i = val; i < 1000000; i++) {
      isprime = true;
      for(j = 2; j < (i/j + 1); j++) {
        if((i%j)==0) {
          isprime = false;
          break;
        }
      }
      if(isprime) {
        val = i;
        break;
      }
    }
    return val;       
  } 
 
  public void reset() { 
    val = start; 
  } 
 
  public void setStart(int x) { 
    start = x; 
    val = start; 
  } 
}

listing 6
// Demonstrate interface references.
 
using System;
 
// Define the interface
public interface ISeries {
  int getNext(); // return next number in series
  void reset(); // restart
  void setStart(int x); // set starting value
}
 
// Use ISeries to generate a sequence of even numbers.
class ByTwos : ISeries {
  int start;
  int val;
 
  public ByTwos() {
    start = 0;
    val = 0;
  } 
 
  public int getNext() {
    val += 2;
    return val;
  }
 
  public void reset() {
    val = start;
  }
 
  public void setStart(int x) {
    start = x;
    val = start;
  }
}
 
// Use ISeries to implement a series of prime numbers. 
class Primes : ISeries { 
  int start; 
  int val; 
 
  public Primes() { 
    start = 2; 
    val = 2; 
  }  
 
  public int getNext() { 
    int i, j;
    bool isprime;
 
    val++;
    for(i = val; i < 1000000; i++) {
      isprime = true;
      for(j = 2; j < (i/j + 1); j++) {
        if((i%j)==0) {
          isprime = false;
          break;
        }
      }
      if(isprime) {
        val = i;
        break;
      }
    }
    return val;       
  } 
 
  public void reset() { 
    val = start; 
  } 
 
  public void setStart(int x) { 
    start = x; 
    val = start; 
  } 
}
 
class SeriesDemo2 {
  public static void Main() {
    ByTwos twoOb = new ByTwos();
    Primes primeOb = new Primes();
    ISeries ob;
 
    for(int i=0; i < 5; i++) {
      ob = twoOb;
      Console.WriteLine("Next ByTwos value is " +
                          ob.getNext());
      ob = primeOb;
      Console.WriteLine("Next prime number is " +
                          ob.getNext());
    }
  }
}

listing 7
// Use a property in an interface.
 
using System;
 
public interface ISeries {
  // An interface property.
  int next {
    get; // return the next number in series
    set; // set next number
  }
}
 
// Implement ISeries.
class ByTwos : ISeries {
  int val;
 
  public ByTwos() {
    val = 0;
  } 
 
  // get or set value
  public int next {
    get { 
      val += 2;
      return val;
    }
    set {
      val = value;
    }
  }
}
 
// Demonstrate an interface property.
class SeriesDemo3 {
  public static void Main() {
    ByTwos ob = new ByTwos();
 
    // access series through a property
    for(int i=0; i < 5; i++)
      Console.WriteLine("Next value is " + ob.next);
 
    Console.WriteLine("\nStarting at 21");
    ob.next = 21;
    for(int i=0; i < 5; i++)
      Console.WriteLine("Next value is " + ob.next);
  }
}

listing 8
// Add an indexer in an interface.
 
using System;
 
public interface ISeries {
  // an interface property
  int next {
    get; // return the next number in series
    set; // set next number
  }
 
  // an interface indexer
  int this[int index] {
    get; // return the specified number in series
  }
}
 
// Implement ISeries.
class ByTwos : ISeries {
  int val;
 
  public ByTwos() {
    val = 0;
  } 
 
  // get or set value using a property
  public int next {
    get { 
      val += 2;
      return val;
    }
    set {
      val = value;
    }
  }
 
  // get a value using an index
  public int this[int index] {
    get { 
      val = 0;
      for(int i=0; i<index; i++)
        val += 2;
      return val;
    }
  }
}
 
// Demonstrate an interface indexer.
class SeriesDemo4 {
  public static void Main() {
    ByTwos ob = new ByTwos();
 
    // access series through a property
    for(int i=0; i < 5; i++)
      Console.WriteLine("Next value is " + ob.next);
 
    Console.WriteLine("\nStarting at 21");
    ob.next = 21;
    for(int i=0; i < 5; i++)
      Console.WriteLine("Next value is " +
                         ob.next);
 
    Console.WriteLine("\nResetting to 0");
    ob.next = 0;
 
    // access series through an indexer
    for(int i=0; i < 5; i++)
      Console.WriteLine("Next value is " + ob[i]);
  }
}

listing 9
// One interface can inherit another.
 
using System;
 
public interface A {
  void meth1();
  void meth2();
}
 
// B now includes meth1() and meth2() -- it adds meth3().
public interface B : A {
  void meth3();
}
 
// This class must implement all of A and B
class MyClass : B {
  public void meth1() {
    Console.WriteLine("Implement meth1().");
  }
 
  public void meth2() {
    Console.WriteLine("Implement meth2().");
  }
 
  public void meth3() {
    Console.WriteLine("Implement meth3().");
  }
}
 
class IFExtend {
  public static void Main() {
    MyClass ob = new MyClass();
 
    ob.meth1();
    ob.meth2();
    ob.meth3();
  }
}

listing 10
interface IMyIF {
  int myMeth(int x);
}

listing 11
class MyClass : IMyIF {
  int IMyIF.myMeth(int x) {
    return x / 3;
  }
}

listing 12
// Explicitly implement an interface member.
 
using System;
 
interface IEven {
  bool isOdd(int x);
  bool isEven(int x);
}
 
class MyClass : IEven {
 
  // Explicit implementation. Notice that this member is private
  // by default.
  bool IEven.isOdd(int x) {
    if((x%2) != 0) return true;
    else return false;
  }
 
  // Normal implementation.
  public bool isEven(int x) {
    IEven o = this; // reference to invoking object
 
    return !o.isOdd(x);
  }
}
 
class Demo {
  public static void Main() {
    MyClass ob = new MyClass();
    bool result;
 
    result = ob.isEven(4);
    if(result) Console.WriteLine("4 is even.");
 
    // result = ob.isOdd(4); // Error, isOdd not directly accessible
 
    // But, this is OK. It creates an IEven reference to a MyClass object
    // and then calls isOdd() through that reference.
    IEven iRef = (IEven) ob;
    result = iRef.isOdd(3);
    if(result) Console.WriteLine("3 is odd.");
 
  }
}

listing 13
// Use explicit implementation to remove ambiguity.
 
using System;
 
interface IMyIF_A {
  int meth(int x);
}
 
interface IMyIF_B {
  int meth(int x);
}
 
// MyClass implements both interfaces.
class MyClass : IMyIF_A, IMyIF_B {
 
  // explicitly implement the two meth()s
  int IMyIF_A.meth(int x) {
    return x + x;
  }
  int IMyIF_B.meth(int x) {
    return x * x;
  }
 
  // call meth() through an interface reference.
  public int methA(int x){
    IMyIF_A a_ob;
    a_ob = this;
    return a_ob.meth(x); // calls IMyIF_A
  }
 
  public int methB(int x){
    IMyIF_B b_ob;
    b_ob = this;
    return b_ob.meth(x); // calls IMyIF_B
  }
}
 
class FQIFNames {
  public static void Main() {
    MyClass ob = new MyClass();
 
    Console.Write("Calling IMyIF_A.meth(): ");
    Console.WriteLine(ob.methA(3));
 
    Console.Write("Calling IMyIF_B.meth(): ");
    Console.WriteLine(ob.methB(3));
  }
}

listing 14
// An encryption interface.
public interface ICipher {
  string encode(string str);
  string decode(string str);
}

listing 15
/* A simple implementation of ICipher that codes
   a message by shifting each character 1 position
   higher.  Thus, A becomes B, and so on. */
class SimpleCipher : ICipher {
    
  // Return an encoded string given plaintext.
  public string encode(string str) {
    string ciphertext = "";
 
    for(int i=0; i < str.Length; i++)
      ciphertext = ciphertext + (char) (str[i] + 1);
 
    return ciphertext;
  }
 
  // Return a decoded string given ciphertext.
  public string decode(string str) {
    string plaintext = "";
 
    for(int i=0; i < str.Length; i++)
      plaintext = plaintext + (char) (str[i] - 1);
 
    return plaintext;
  }
}
 
/* This implementation of ICipher uses bit
   manipulations and key. */
class BitCipher : ICipher {
  ushort key;
 
  // Specify a key when constructing BitCiphers.
  public BitCipher(ushort k) {
    key = k;
  }
    
  // Return an encoded string given plaintext.
  public string encode(string str) {
    string ciphertext = "";
 
    for(int i=0; i < str.Length; i++)
      ciphertext = ciphertext + (char) (str[i] ^ key);
 
    return ciphertext;
  }
 
  // Return adecoded string given ciphertext.
  public string decode(string str) {
    string plaintext = "";
 
    for(int i=0; i < str.Length; i++)
      plaintext = plaintext + (char) (str[i] ^ key);
 
    return plaintext;
  }
}

listing 16
// Demonstrate ICipher.
 
using System;
 
class ICipherDemo {
  public static void Main() {
    ICipher ciphRef;
    BitCipher bit = new BitCipher(27);
    SimpleCipher sc = new SimpleCipher();
 
    string plain;
    string coded;
 
    // first, ciphRef refers to the simple cipher
    ciphRef = sc;
 
    Console.WriteLine("Using simple cipher.");
 
    plain = "testing";
    coded = ciphRef.encode(plain);
    Console.WriteLine("Cipher text: " + coded);
 
    plain = ciphRef.decode(coded);
    Console.WriteLine("Plain text: " + plain);
 
    // now, let ciphRef refer to the bitwise cipher
    ciphRef = bit;
 
    Console.WriteLine("\nUsing bitwise cipher.");
 
    plain = "testing";
    coded = ciphRef.encode(plain);
    Console.WriteLine("Cipher text: " + coded);
 
    plain = ciphRef.decode(coded);
    Console.WriteLine("Plain text: " + plain);
  }
}

listing 17
// Use ICipher.
 
using System;
 
// A class for storing unlisted telephone numbers.
class UnlistedPhone {
  string pri_name;   // supports name property
  string pri_number; // supports number property
 
  ICipher crypt; // reference to encryption object
 
  public UnlistedPhone(string name, string number, ICipher c)
  {
    crypt = c; // store encryption object
 
    pri_name = crypt.encode(name);
    pri_number = crypt.encode(number);
  }
 
  public string Name {
    get {
      return crypt.decode(pri_name);
    }
    set {
      pri_name = crypt.encode(value);
    }
  }
 
  public string Number {
    get {
      return crypt.decode(pri_number);
    }
    set {
      pri_number = crypt.encode(value);
    }
  }
}
 
// Demonstrate UnlistedPhone
class UnlistedDemo {
  public static void Main() {
    UnlistedPhone phone1 =
        new UnlistedPhone("Tom", "555-3456", new BitCipher(27)); 
    UnlistedPhone phone2 =
        new UnlistedPhone("Mary", "555-8891", new BitCipher(9));
 
    Console.WriteLine("Unlisted number for " + 
                      phone1.Name + " is " +
                      phone1.Number); 
 
    Console.WriteLine("Unlisted number for " + 
                      phone2.Name + " is " +
                      phone2.Number); 
  }
}

listing 18
// This version uses SimpleCipher.
 
class UnlistedDemo {
  public static void Main() {
 
    // now, use SimpleCipher rather than BitCipher
    UnlistedPhone phone1 =
        new UnlistedPhone("Tom", "555-3456", new SimpleCipher()); 
    UnlistedPhone phone2 =
        new UnlistedPhone("Mary", "555-8891", new SimpleCipher());
 
    Console.WriteLine("Unlisted number for " + 
                      phone1.Name + " is " +
                      phone1.Number); 
 
    Console.WriteLine("Unlisted number for " + 
                      phone2.Name + " is " +
                      phone2.Number); 
  }
}

listing 19
// Demonstrate a structure.
 
using System;
 
// Define a structure.
struct Book {
  public string author;
  public string title;
  public int copyright;
 
  public Book(string a, string t, int c) {
    author = a;
    title = t;
    copyright = c;
  }
}
 
// Demonstrate Book structure.
class StructDemo {
  public static void Main() {
    Book book1 = new Book("Herb Schildt",
                          "C#: The Complete Reference",
                          2005); // explicit constructor
 
    Book book2 = new Book(); // default constructor
    Book book3; // no constructor
 
    Console.WriteLine(book1.title + " by " + book1.author +
                      ", (c) " + book1.copyright);
    Console.WriteLine();
 
    if(book2.title == null)
      Console.WriteLine("book2.title is null.");
    // now, give book2 some info
    book2.title = "Brave New World";
    book2.author = "Aldous Huxley";
    book2.copyright = 1932;
    Console.Write("book2 now contains: ");
    Console.WriteLine(book2.title + " by " + book2.author +
                      ", (c) " + book2.copyright);
 
    Console.WriteLine();
 
// Console.WriteLine(book3.title); // error, must initialize first
    book3.title = "Red Storm Rising";
 
    Console.WriteLine(book3.title); // now OK
  }
}

listing 20
// Copy a struct.
 
using System;
 
// Define a structure.
struct MyStruct {
  public int x;
}
 
// Demonstrate structure assignment.
class StructAssignment {
  public static void Main() {
    MyStruct a;
    MyStruct b;
 
    a.x = 10;
    b.x = 20;
 
    Console.WriteLine("a.x {0}, b.x {1}", a.x, b.x);
 
    a = b;
    b.x = 30;
 
    Console.WriteLine("a.x {0}, b.x {1}", a.x, b.x);
  }
}

listing 21
// Copy a class.
 
using System;
 
// Define a structure.
class MyClass {
  public int x;
}
 
// Now show a class object assignment.
class ClassAssignment {
  public static void Main() {
    MyClass a = new MyClass();
    MyClass b = new MyClass();
 
    a.x = 10;
    b.x = 20;
 
    Console.WriteLine("a.x {0}, b.x {1}", a.x, b.x);
 
    a = b;
    b.x = 30;
 
    Console.WriteLine("a.x {0}, b.x {1}", a.x, b.x);
  }
}

listing 22
// Structures are good when grouping data.
 
using System;
 
// Define a packet structure.
struct PacketHeader {
  public uint packNum; // packet number
  public ushort packLen; // length of packet
}
 
// Use PacketHeader to create an e-commerce transaction record.
class Transaction {
  static uint transacNum = 0;
 
  PacketHeader ph;  // incorporate PacketHeader into Transaction
  string accountNum;
  double amount;
 
  public Transaction(string acc, double val) {
   // create packet header
    ph.packNum = transacNum++; 
    ph.packLen = 512;  // arbitrary length
 
    accountNum = acc;
    amount = val;
  }
 
  // Simulate a transaction.
  public void sendTransaction() {
    Console.WriteLine("Packet #: " + ph.packNum +
                      ", Length: " + ph.packLen +
                      ",\n    Account #: " + accountNum +
                      ", Amount: {0:C}\n", amount);
  }
}
 
// Demonstrate Packet
class PacketDemo {
  public static void Main() {
    Transaction t = new Transaction("31243", -100.12);
    Transaction t2 = new Transaction("AB4655", 345.25);
    Transaction t3 = new Transaction("8475-09", 9800.00);
 
    t.sendTransaction();
    t2.sendTransaction();
    t3.sendTransaction();
  }
}

listing 23
// Demonstrate an enumeration.
 
using System;
 
class EnumDemo {
  enum Apple { Jonathan, GoldenDel, RedDel, Winesap,
               Cortland, McIntosh };
 
  public static void Main() {
    string[] color = {
      "Red",
      "Yellow",
      "Red",
      "Red",
      "Red",
      "Reddish Green"
    };
 
    Apple i; // declare an enum variable
 
    // use i to cycle through the enum
    for(i = Apple.Jonathan; i <= Apple.McIntosh; i++) 
      Console.WriteLine(i + " has value of " + (int)i);
 
    Console.WriteLine();
 
    // use an enumeration to index an array
    for(i = Apple.Jonathan; i <= Apple.McIntosh; i++) 
      Console.WriteLine("Color of " + i + " is " +
                         color[(int)i]);
 
  }
}

listing 24
// Simulate a conveyor belt
 
using System;
 
class ConveyorControl {
  // enumerate the conveyor commands
  public enum Action { start, stop, forward, reverse };
 
  public void conveyor(Action com) {
    switch(com) {
      case Action.start:
        Console.WriteLine("Starting conveyor.");
        break;
      case Action.stop:
        Console.WriteLine("Stopping conveyor.");
        break;
      case Action.forward:
        Console.WriteLine("Moving forward.");
        break;
      case Action.reverse:
        Console.WriteLine("Moving backward.");
        break;
    }
  }
}
 
class ConveyorDemo {
  public static void Main() {
    ConveyorControl c = new ConveyorControl();
 
    c.conveyor(ConveyorControl.Action.start);
    c.conveyor(ConveyorControl.Action.forward);
    c.conveyor(ConveyorControl.Action.reverse);
    c.conveyor(ConveyorControl.Action.stop);
    
  }
}

listing 1
// Demonstrate exception handling.
 
using System;
 
class ExcDemo1 {
  public static void Main() {
    int[] nums = new int[4];
 
    try {
      Console.WriteLine("Before exception is generated.");
 
      // Generate an index out-of-bounds exception.
      for(int i=0; i < 10; i++) {
        nums[i] = i;
        Console.WriteLine("nums[{0}]: {1}", i, nums[i]);
      }
 
      Console.WriteLine("this won't be displayed");
    }
    catch (IndexOutOfRangeException) {
      // catch the exception
      Console.WriteLine("Index out-of-bounds!");
    }
    Console.WriteLine("After catch statement.");
  }
}

listing 2
/* An exception can be generated by one
   method and caught by another. */
 
using System;
 
class ExcTest {
  // Generate an exception.
  public static void genException() {
    int[] nums = new int[4]; 
 
    Console.WriteLine("Before exception is generated.");
 
    // Generate an index out-of-bounds exception.
    for(int i=0; i < 10; i++) {
      nums[i] = i;
      Console.WriteLine("nums[{0}]: {1}", i, nums[i]);
    }
 
    Console.WriteLine("this won't be displayed"); 
  }
}    
 
class ExcDemo2 { 
  public static void Main() { 
 
    try { 
      ExcTest.genException();
    } 
    catch (IndexOutOfRangeException) { 
      // catch the exception 
      Console.WriteLine("Index out-of-bounds!"); 
    } 
    Console.WriteLine("After catch statement."); 
  } 
}

listing 3
// Let the C# runtime system handle the error.
 
using System;
 
class NotHandled {
  public static void Main() {
    int[] nums = new int[4];
 
    Console.WriteLine("Before exception is generated.");
 
    // Generate an index out-of-bounds exception.
    for(int i=0; i < 10; i++) {
      nums[i] = i;
      Console.WriteLine("nums[{0}]: {1}", i, nums[i]);
    }
 
  }
}

listing 4
// This won't work!
 
using System;
 
class ExcTypeMismatch { 
  public static void Main() { 
    int[] nums = new int[4]; 
 
    try { 
      Console.WriteLine("Before exception is generated.");
 
      // Generate an index out-of-bounds exception.
      for(int i=0; i < 10; i++) {
        nums[i] = i;
        Console.WriteLine("nums[{0}]: {1}", i, nums[i]);
      }
 
      Console.WriteLine("this won't be displayed"); 
    } 
 
    /* Can't catch an array boundary error with a
       DivideByZeroException. */
    catch (DivideByZeroException) { 
      // catch the exception 
      Console.WriteLine("Index out-of-bounds!"); 
    } 
    Console.WriteLine("After catch statement."); 
  } 
}

listing 5
// Handle error gracefully and continue.
 
using System;
 
class ExcDemo3 {
  public static void Main() {
    int[] numer = { 4, 8, 16, 32, 64, 128 };
    int[] denom = { 2, 0, 4, 4, 0, 8 };
 
    for(int i=0; i < numer.Length; i++) {
      try {
        Console.WriteLine(numer[i] + " / " +
                          denom[i] + " is " +
                          numer[i]/denom[i]);
      }
      catch (DivideByZeroException) {
        // catch the exception
        Console.WriteLine("Can't divide by Zero!");
      }
    }
  }
}

listing 6
// Use multiple catch statements.
 
using System;
 
class ExcDemo4 {
  public static void Main() {
    // Here, numer is longer than denom.
    int[] numer = { 4, 8, 16, 32, 64, 128, 256, 512 };
    int[] denom = { 2, 0, 4, 4, 0, 8 };
 
    for(int i=0; i < numer.Length; i++) {
      try {
        Console.WriteLine(numer[i] + " / " +
                           denom[i] + " is " +
                           numer[i]/denom[i]);
      }
      catch (DivideByZeroException) {
        // catch the exception
        Console.WriteLine("Can't divide by Zero!");
      }
      catch (IndexOutOfRangeException) {
        // catch the exception
        Console.WriteLine("No matching element found.");
      }
    }
  }
}

listing 7
// Use the "catch all" catch statement.
 
using System;
 
class ExcDemo5 {
  public static void Main() {
    // Here, numer is longer than denom.
    int[] numer = { 4, 8, 16, 32, 64, 128, 256, 512 };
    int[] denom = { 2, 0, 4, 4, 0, 8 };
 
    for(int i=0; i < numer.Length; i++) {
      try {
        Console.WriteLine(numer[i] + " / " +
                           denom[i] + " is " +
                           numer[i]/denom[i]);
      }
      catch {
        Console.WriteLine("Some exception occurred.");
      }
    }
  }
}

listing 8
// Use a nested try block.
 
using System;
 
class NestTrys {
  public static void Main() {
    // Here, numer is longer than denom.
    int[] numer = { 4, 8, 16, 32, 64, 128, 256, 512 };
    int[] denom = { 2, 0, 4, 4, 0, 8 };
 
    try { // outer try
      for(int i=0; i < numer.Length; i++) {
        try { // nested try
          Console.WriteLine(numer[i] + " / " +
                             denom[i] + " is " +
                             numer[i]/denom[i]);
        }
        catch (DivideByZeroException) {
          // catch the exception
          Console.WriteLine("Can't divide by Zero!");
        }
      }
    } 
    catch (IndexOutOfRangeException) {
      // catch the exception
      Console.WriteLine("No matching element found.");
      Console.WriteLine("Fatal error -- program terminated.");
    }
  }
}

listing 9
// Manually throw an exception.
 
using System;
 
class ThrowDemo {
  public static void Main() {
    try {
      Console.WriteLine("Before throw.");
      throw new DivideByZeroException();
    }
    catch (DivideByZeroException) {
      // catch the exception
      Console.WriteLine("Exception caught.");
    }
    Console.WriteLine("After try/catch block.");
  }
}

listing 10
// Rethrow an exception.
 
using System;
 
class Rethrow {
  public static void genException() {
    // here, numer is longer than denom
    int[] numer = { 4, 8, 16, 32, 64, 128, 256, 512 };
    int[] denom = { 2, 0, 4, 4, 0, 8 };
 
    for(int i=0; i<numer.Length; i++) {
      try {
        Console.WriteLine(numer[i] + " / " +
                          denom[i] + " is " +
                          numer[i]/denom[i]);
      }
      catch (DivideByZeroException) {
        // catch the exception
        Console.WriteLine("Can't divide by Zero!");
      }
      catch (IndexOutOfRangeException) {
        // catch the exception
        Console.WriteLine("No matching element found.");
        throw; // rethrow the exception
      }
    }
  }  
}
 
class RethrowDemo {
  public static void Main() {
    try {
      Rethrow.genException();
    }
    catch(IndexOutOfRangeException) {
      // recatch exception
     Console.WriteLine("Fatal error -- " +
                       "program terminated.");
    }
  }
}

listing 11
// Use finally.
 
using System;
 
class UseFinally {
  public static void genException(int what) {
    int t;
    int[] nums = new int[2];
 
    Console.WriteLine("Receiving " + what);
    try {
      switch(what) {
        case 0: 
          t = 10 / what; // generate div-by-zero error
          break;
        case 1:
          nums[4] = 4; // generate array index error.
          break;
        case 2:
          return; // return from try block
      }
    }
    catch (DivideByZeroException) {
      // catch the exception
      Console.WriteLine("Can't divide by Zero!");
      return; // return from catch
    }
    catch (IndexOutOfRangeException) {
      // catch the exception
      Console.WriteLine("No matching element found.");
    }
    finally {
      Console.WriteLine("Leaving try.");
    }
  }  
}
 
class FinallyDemo {
  public static void Main() {
    
    for(int i=0; i < 3; i++) {
      UseFinally.genException(i);
      Console.WriteLine();
    }
  }
}

listing 12
// Using Exception members.
 
using System;
 
class ExcTest {
  public static void genException() {
    int[] nums = new int[4]; 
 
    Console.WriteLine("Before exception is generated.");
 
    // Generate an index out-of-bounds exception.
      for(int i=0; i < 10; i++) {
        nums[i] = i;
        Console.WriteLine("nums[{0}]: {1}", i, nums[i]);
      }
 
    Console.WriteLine("this won't be displayed"); 
  }
}    
 
class UseExcept { 
  public static void Main() { 
 
    try { 
      ExcTest.genException();
    } 
    catch (IndexOutOfRangeException exc) { 
      // catch the exception 
      Console.WriteLine("Standard message is: ");
      Console.WriteLine(exc); // calls ToString()
      Console.WriteLine("Stack trace: " + exc.StackTrace);
      Console.WriteLine("Message: " + exc.Message);
      Console.WriteLine("TargetSite: " + exc.TargetSite);
    } 
    Console.WriteLine("After catch statement."); 
  } 
}

listing 13
// Use the NullReferenceException.
 
using System; 
 
class X {
  int x;
  public X(int a) {
    x = a;
  }
 
  public int add(X o) {
    return x + o.x;
  }
}
  
// Demonstrate NullReferenceException.
class NREDemo {  
  public static void Main() {  
    X p = new X(10);
    X q = null; // q is explicitly assigned null
    int val;
 
    try {
      val = p.add(q); // this will lead to an exception
    } catch (NullReferenceException) {
      Console.WriteLine("NullReferenceException!");
      Console.WriteLine("fixing...\n");
 
      // now, fix it
      q = new X(9);  
      val = p.add(q);
    }
 
    Console.WriteLine("val is {0}", val);
 
  } 
}

listing 14
// Use a custom Exception for RangeArray errors.
 
using System; 
 
// Create a RangeArray exception.
class RangeArrayException : ApplicationException {
  // Implement the standard constructors
  public RangeArrayException() : base() { }
  public RangeArrayException(string str) : base(str) { } 
 
  // Override ToString for RangeArrayException.
  public override string ToString() {
    return Message;
  }
}
 
// An improved version of RangeArray.
class RangeArray {  
  // private data
  int[] a; // reference to underlying array  
  int lowerBound; // lowest index
  int upperBound; // greatest index
 
  int len; // underlying var for Length property
   
  // Construct array given its size. 
  public RangeArray(int low, int high) { 
    high++;
    if(high <= low) {
      throw new RangeArrayException("Low index not less than high.");
    }
    a = new int[high - low]; 
    len = high - low;  
 
    lowerBound = low;
    upperBound = --high;
  } 
 
  // Read-only Length property. 
  public int Length { 
    get { 
      return len; 
    } 
  } 
 
  // This is the indexer for RangeArray. 
  public int this[int index] { 
    // This is the get accessor. 
    get { 
      if(ok(index)) { 
        return a[index - lowerBound]; 
      } else { 
        throw new RangeArrayException("Range Error.");
      }
    } 
 
    // This is the set accessor.
    set { 
      if(ok(index)) { 
        a[index - lowerBound] = value; 
      } 
      else throw new RangeArrayException("Range Error.");
    } 
  } 
 
  // Return true if index is within bounds. 
  private bool ok(int index) { 
    if(index >= lowerBound & index <= upperBound) return true; 
    return false; 
  } 
}  
  
// Demonstrate the index-range array. 
class RangeArrayDemo {  
  public static void Main() {  
    try {
      RangeArray ra = new RangeArray(-5, 5); 
      RangeArray ra2 = new RangeArray(1, 10); 
 
      // Demonstrate ra
      Console.WriteLine("Length of ra: " + ra.Length);
 
      for(int i = -5; i <= 5; i++)
        ra[i] = i;
  
      Console.Write("Contents of ra: ");
      for(int i = -5; i <= 5; i++)
        Console.Write(ra[i] + " ");
 
      Console.WriteLine("\n");
 
      // Demonstrate ra2
      Console.WriteLine("Length of ra2: " + ra2.Length);
 
      for(int i = 1; i <= 10; i++)
        ra2[i] = i;
 
      Console.Write("Contents of ra2: ");
      for(int i = 1; i <= 10; i++)
        Console.Write(ra2[i] + " ");
 
      Console.WriteLine("\n");
 
    } catch (RangeArrayException exc) {
       Console.WriteLine(exc);
    }
 
    // Now, demonstrate some errors.
    Console.WriteLine("Now generate some range errors.");
 
    // Use an invalid constructor.
    try {
      RangeArray ra3 = new RangeArray(100, -10); // Error
  
    } catch (RangeArrayException exc) {
       Console.WriteLine(exc);
    }
 
    // Use an invalid index.
    try {
      RangeArray ra3 = new RangeArray(-2, 2); 
 
      for(int i = -2; i <= 2; i++)
        ra3[i] = i;
 
      Console.Write("Contents of ra3: ");
      for(int i = -2; i <= 10; i++) // generate range error
        Console.Write(ra3[i] + " ");
 
    } catch (RangeArrayException exc) {
       Console.WriteLine(exc);
    }
  } 
}

listing 15
// Derived exceptions must appear before base class exceptions.
 
using System;
 
// Create an exception.
class ExceptA : ApplicationException {
  public ExceptA() : base() { }
  public ExceptA(string str) : base(str) { }
 
  public override string ToString() {
    return Message;
  }
}
 
// Create an exception derived from ExceptA
class ExceptB : ExceptA {
  public ExceptB() : base() { }
  public ExceptB(string str) : base(str) { }
 
  public override string ToString() {
    return Message; 
  }
}
 
class OrderMatters {
  public static void Main() {
    for(int x = 0; x < 3; x++) {
      try {
        if(x==0) throw new ExceptA("Caught an ExceptA exception");
        else if(x==1) throw new ExceptB("Caught an ExceptB exception");
        else throw new Exception();
      }
      catch (ExceptB exc) {
        // catch the exception
        Console.WriteLine(exc);
      }
      catch (ExceptA exc) {
        // catch the exception
        Console.WriteLine(exc);
      }
      catch (Exception exc) {
        Console.WriteLine(exc);
      }
    }
  }
}

listing 16
// Using checked and unchecked.
 
using System;
 
class CheckedDemo { 
  public static void Main() { 
    byte a, b;
    byte result;
 
    a = 127;
    b = 127;
 
    try { 
      result = unchecked((byte)(a * b));
      Console.WriteLine("Unchecked result: " + result);
 
      result = checked((byte)(a * b)); // this causes exception
      Console.WriteLine("Checked result: " + result); // won't execute
    } 
    catch (OverflowException exc) { 
      // catch the exception 
      Console.WriteLine(exc);
    } 
  } 
}

listing 17
// Using checked and unchecked with statement blocks.
 
using System;
 
class CheckedBlocks { 
  public static void Main() { 
    byte a, b;
    byte result;
 
    a = 127;
    b = 127;
 
    try { 
      unchecked {
        a = 127;
        b = 127;
        result = unchecked((byte)(a * b));
        Console.WriteLine("Unchecked result: " + result);
 
        a = 125;
        b = 5;
        result = unchecked((byte)(a * b));
        Console.WriteLine("Unchecked result: " + result);
      }
 
      checked {
        a = 2;
        b = 7;
        result = checked((byte)(a * b)); // this is OK
        Console.WriteLine("Checked result: " + result);
 
        a = 127;
        b = 127;
        result = checked((byte)(a * b)); // this causes exception
        Console.WriteLine("Checked result: " + result); // won't execute
      }
    } 
    catch (OverflowException exc) { 
      // catch the exception 
      Console.WriteLine(exc);
    } 
  } 
}

listing 1
// Read a character from the keyboard.
 
using System;
 
class KbIn {  
  public static void Main() {
    char ch;
 
    Console.Write("Press a key followed by ENTER: ");
 
    ch = (char) Console.Read(); // get a char
   
    Console.WriteLine("Your key is: " + ch);
  }  
}

listing 2
// Input from the console using ReadLine().
 
using System; 
 
class ReadString {
  public static void Main() {
    string str;
 
    Console.WriteLine("Enter some characters.");
    str = Console.ReadLine();
    Console.WriteLine("You entered: " + str);
  }
}

listing 3
// Read a string from the keyboard, using Console.In directly. 
 
using System; 
 
class ReadChars2 {
  public static void Main() {
    string str;
 
    Console.WriteLine("Enter some characters.");
 
    str = Console.In.ReadLine(); // call TextReader's ReadLine() method
 
    Console.WriteLine("You entered: " + str);
  }
}

listing 4
// Read keystrokes from the console by
// using ReadKey().
 
using System; 
 
class ReadKeys {   
  public static void Main() { 
    ConsoleKeyInfo keypress;
 
    Console.WriteLine("Enter keystrokes. Enter Q to stop.");
 
    do {
      keypress = Console.ReadKey(); // read keystrokes
    
      Console.WriteLine(" Your key is: " + keypress.KeyChar); 
 
      // Check for modifier keys.
      if((ConsoleModifiers.Alt & keypress.Modifiers) != 0)
        Console.WriteLine("Alt key pressed.");
      if((ConsoleModifiers.Control & keypress.Modifiers) != 0)
        Console.WriteLine("Control key pressed.");
      if((ConsoleModifiers.Shift & keypress.Modifiers) != 0)
        Console.WriteLine("Shift key pressed.");
 
    } while(keypress.KeyChar != 'Q');
  }   
}

listing 5
// Write to Console.Out and Console.Error.
 
using System;
 
class ErrOut {
  public static void Main() {
    int a=10, b=0;
    int result;
 
    Console.Out.WriteLine("This will generate an exception.");
    try {
      result = a / b; // generate an exception
    } catch(DivideByZeroException exc) {
      Console.Error.WriteLine(exc.Message);
    }
  }
}

listing 6
FileStream fin;
 
try {
  fin = new FileStream("test.dat", FileMode.Open);
}
catch(FileNotFoundException exc) {
  Console.WriteLine(exc.Message);
  return;
}
catch {
  Console.WriteLine("Cannot open file.");
  return;
}

listing 7
/* Display a text file.
 
   To use this program, specify the name 
   of the file that you want to see.
   For example, to see a file called TEST.CS,
   use the following command line.
 
   ShowFile TEST.CS
*/
 
using System;
using System.IO; 
 
class ShowFile {
  public static void Main(string[] args) {
    int i;
    FileStream fin;
 
    try {
      fin = new FileStream(args[0], FileMode.Open);
    } catch(FileNotFoundException exc) {
      Console.WriteLine(exc.Message);
      return;
    } catch(IndexOutOfRangeException exc) {
      Console.WriteLine(exc.Message + "\nUsage: ShowFile File");
      return;
    }
 
    // read bytes until EOF is encountered
    do {
      try {
        i = fin.ReadByte();
      } catch(Exception exc) {
        Console.WriteLine(exc.Message);
        return;
      }
      if(i != -1) Console.Write((char) i);
    } while(i != -1);
 
    fin.Close();
  }
}

listing 8
// Write to a file.
 
using System;
using System.IO; 
 
class WriteToFile {
  public static void Main(string[] args) {
    FileStream fout;
 
    // open output file
    try {
      fout = new FileStream("test.txt", FileMode.Create);
    } catch(IOException exc) {
      Console.WriteLine(exc.Message + "\nError Opening Output File");
      return;
    }
 
    // Write the alphabet to the file.
    try {
      for(char c = 'A'; c <= 'Z'; c++)
        fout.WriteByte((byte) c);
    } catch(IOException exc) {
      Console.WriteLine(exc.Message + "File Error");
    }
 
    fout.Close();
  }
}

listing 9
/* Copy a file.
 
   To use this program, specify the name 
   of the source file and the destination file.
   For example, to copy a file called FIRST.DAT
   to a file called SECOND.DAT, use the following
   command line.
 
   CopyFile FIRST.DAT SECOND.DAT
*/
 
using System;
using System.IO; 
 
class CopyFile {
  public static void Main(string[] args) {
    int i;
    FileStream fin;
    FileStream fout;
 
    try {
      // open input file
      try {
        fin = new FileStream(args[0], FileMode.Open);
      } catch(FileNotFoundException exc) {
        Console.WriteLine(exc.Message + "\nInput File Not Found");
        return;
      }
 
      // open output file
      try {
        fout = new FileStream(args[1], FileMode.Create);
      } catch(IOException exc) {
        Console.WriteLine(exc.Message + "\nError Opening Output File");
        return;
      }
    } catch(IndexOutOfRangeException exc) {
      Console.WriteLine(exc.Message + "\nUsage: CopyFile From To");
      return;
    }
 
    // Copy File
    try {
      do {
        i = fin.ReadByte();
        if(i != -1) fout.WriteByte((byte)i);
      } while(i != -1);
    } catch(IOException exc) {
      Console.WriteLine(exc.Message + "File Error");
    }
 
    fin.Close();
    fout.Close();
  }
}

listing 10
/* A simple key-to-disk utility that
   demonstrates a StreamWriter. */
 
using System;
using System.IO;
 
class KtoD {
  public static void Main() {
    string str;
    FileStream fout;
 
    try {
      fout = new FileStream("test.txt", FileMode.Create);
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "Cannot open file.");
      return ;
    }
    StreamWriter fstr_out = new StreamWriter(fout);
 
    Console.WriteLine("Enter text ('stop' to quit).");
    do {
      Console.Write(": ");
      str = Console.ReadLine();
 
      if(str != "stop") {
        str = str + "\r\n"; // add newline
        try {
          fstr_out.Write(str);
        } catch(IOException exc) {
          Console.WriteLine(exc.Message + "File Error");
          return ;
        }
      }
    } while(str != "stop");
 
    fstr_out.Close();
  }
}

listing 11
// Open a file using StreamWriter. 
 
using System;
using System.IO;
 
class KtoD {
  public static void Main() {
    string str;
    StreamWriter fstr_out;
 
    // Open the file directly using StreamWriter.
    try {
      fstr_out = new StreamWriter("test.txt");
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "Cannot open file.");
      return ;
    }
 
    Console.WriteLine("Enter text ('stop' to quit).");
    do {
      Console.Write(": ");
      str = Console.ReadLine();
 
      if(str != "stop") {
        str = str + "\r\n"; // add newline
        try {
          fstr_out.Write(str);
        } catch(IOException exc) {
          Console.WriteLine(exc.Message + "File Error");
          return ;
        }
      }
    } while(str != "stop");
 
    fstr_out.Close();
  }
}

listing 12
/* A simple disk-to-screen utility that
   demonstrates a FileReader. */
 
using System;
using System.IO; 
 
class DtoS {
  public static void Main() {
    FileStream fin;
    string s;
 
    try {
      fin = new FileStream("test.txt", FileMode.Open);
    }
    catch(FileNotFoundException exc) {
      Console.WriteLine(exc.Message + "Cannot open file.");
      return ;
    } 
 
    StreamReader fstr_in = new StreamReader(fin);
 
    // Read the file line-by-line.
    while((s = fstr_in.ReadLine()) != null) {
      Console.WriteLine(s);
    }
 
    fstr_in.Close();
  }
}

listing 13
using System; 
 
class Test {
  public static void Main() {
    Console.WriteLine("This is a test.");
  }
}

listing 14
// Redirect Console.Out.
 
using System; 
using System.IO;
 
class Redirect {
  public static void Main() {
    StreamWriter log_out;
 
    try {
      log_out = new StreamWriter("logfile.txt");
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "Cannot open file.");
      return ;
    }
   
    // Direct standard output to the log file.
    Console.SetOut(log_out);
    Console.WriteLine("This is the start of the log file.");
 
    for(int i=0; i<10; i++) Console.WriteLine(i);
 
    Console.WriteLine("This is the end of the log file.");
    log_out.Close();
  }
}

listing 15
// Write and then read back binary data.
 
using System;
using System.IO; 
 
class RWData {
  public static void Main() {
    BinaryWriter dataOut;
    BinaryReader dataIn;
 
    int i = 10;
    double d = 1023.56;
    bool b = true;
 
    try {
      dataOut = new
        BinaryWriter(new FileStream("testdata", FileMode.Create));
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "\nCannot open file.");
      return;
    }
 
    try {
      Console.WriteLine("Writing " + i);
      dataOut.Write(i); 
 
      Console.WriteLine("Writing " + d);
      dataOut.Write(d);
 
      Console.WriteLine("Writing " + b);
      dataOut.Write(b);
 
      Console.WriteLine("Writing " + 12.2 * 7.4);
      dataOut.Write(12.2 * 7.4);
 
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "\nWrite error.");
    }
 
    dataOut.Close();
 
    Console.WriteLine();
 
    // Now, read them back.
    try {
      dataIn = new
          BinaryReader(new FileStream("testdata", FileMode.Open));
    }
    catch(FileNotFoundException exc) {
      Console.WriteLine(exc.Message + "\nCannot open file.");
      return;
    }
 
    try {
      i = dataIn.ReadInt32();
      Console.WriteLine("Reading " + i);
 
      d = dataIn.ReadDouble();
      Console.WriteLine("Reading " + d);
 
      b = dataIn.ReadBoolean();
      Console.WriteLine("Reading " + b);
 
      d = dataIn.ReadDouble();
      Console.WriteLine("Reading " + d);
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "Read error.");
    }
 
    dataIn.Close(); 
  }
}

listing 16
/* Use BinaryReader and BinaryWriter to implement
   a simple inventory program. */
 
using System;
using System.IO; 
 
class Inventory {
  public static void Main() {
    BinaryWriter dataOut;
    BinaryReader dataIn;
 
    string item; // name of item
    int onhand;  // number on hand
    double cost; // cost
 
    try {
      dataOut = new
        BinaryWriter(new FileStream("inventory.dat",
                                    FileMode.Create));
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "\nCannot open file.");
      return;
    }
 
    // Write some inventory data to the file.
    try {
      dataOut.Write("Hammers"); 
      dataOut.Write(10);
      dataOut.Write(3.95);
 
      dataOut.Write("Screwdrivers"); 
      dataOut.Write(18);
      dataOut.Write(1.50);
 
      dataOut.Write("Pliers"); 
      dataOut.Write(5);
      dataOut.Write(4.95);
 
      dataOut.Write("Saws"); 
      dataOut.Write(8);
      dataOut.Write(8.95);
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "\nWrite error.");
    }
 
    dataOut.Close();
 
    Console.WriteLine();
 
    // Now, open inventory file for reading.
    try {
      dataIn = new
          BinaryReader(new FileStream("inventory.dat",
                       FileMode.Open));
    }
    catch(FileNotFoundException exc) {
      Console.WriteLine(exc.Message + "\nCannot open file.");
      return;
    }
 
    // Lookup item entered by user.
    Console.Write("Enter item to lookup: ");
    string what = Console.ReadLine();
    Console.WriteLine();
 
    try {
      for(;;) {
        // Read an inventory entry.
        item = dataIn.ReadString();
        onhand = dataIn.ReadInt32();
        cost = dataIn.ReadDouble();
 
        /* See if the item matches the one requested.
           If so, display information */
        if(item.CompareTo(what) == 0) {
          Console.WriteLine(onhand + " " + item + " on hand. " +
                            "Cost: {0:C} each", cost);
          Console.WriteLine("Total value of {0}: {1:C}." ,
                            item, cost * onhand);
          break;
        }
      }
    }
    catch(EndOfStreamException) {
      Console.WriteLine("Item not found.");
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message + "Read error.");
    }
 
    dataIn.Close(); 
  }
}

listing 17
// Demonstrate random access.
 
using System;
using System.IO; 
 
class RandomAccessDemo {
  public static void Main() {
    FileStream f;
    char ch;
 
    try {
      f = new FileStream("random.dat", FileMode.Create);
    }
    catch(IOException exc) {
      Console.WriteLine(exc.Message);
      return ;
    }
 
    // Write the alphabet.     
    for(int i=0; i < 26; i++) {
      try {
        f.WriteByte((byte)('A'+i));
      } 
      catch(IOException exc) {
        Console.WriteLine(exc.Message);
        return ;
      }
    }
 
    try {
      // Now, read back specific values
      f.Seek(0, SeekOrigin.Begin); // seek to first byte
      ch = (char) f.ReadByte();
      Console.WriteLine("First value is " + ch);
 
      f.Seek(1, SeekOrigin.Begin); // seek to second byte
      ch = (char) f.ReadByte();
      Console.WriteLine("Second value is " + ch);
 
      f.Seek(4, SeekOrigin.Begin); // seek to 5th byte
      ch = (char) f.ReadByte();
      Console.WriteLine("Fifth value is " + ch);
 
      Console.WriteLine();
 
      // Now, read every other value.
      Console.WriteLine("Here is every other value: ");
      for(int i=0; i < 26; i += 2) {
        f.Seek(i, SeekOrigin.Begin); // seek to ith double
        ch = (char) f.ReadByte();
        Console.Write(ch + " ");
      }
    } 
    catch(IOException exc) {
      Console.WriteLine(exc.Message);
    }
 
    Console.WriteLine();
    f.Close();
  }
}

listing 18
// Demonstrate MemoryStream.
 
using System;
using System.IO;
  
class MemStrDemo {  
  public static void Main() {  
    byte[] storage = new byte[255];
 
    // Create a memory-based stream.
    MemoryStream memstrm = new MemoryStream(storage);
 
    // Wrap memstrm in a reader and a writer.
    StreamWriter memwtr = new StreamWriter(memstrm);
    StreamReader memrdr = new StreamReader(memstrm);
 
    // Write to storage, through memwtr.
    for(int i=0; i < 10; i++)
       memwtr.WriteLine("byte [" + i + "]: " + i);
 
    // put a period at the end
    memwtr.WriteLine(".");
 
    memwtr.Flush();
 
    Console.WriteLine("Reading from storage directly: ");
 
    // Display contents of storage directly.
    foreach(char ch in storage) {
      if (ch == '.') break;
      Console.Write(ch);
    }
 
    Console.WriteLine("\nReading through memrdr: ");
 
    // Read from memstrm using the stream reader.
    memstrm.Seek(0, SeekOrigin.Begin); // reset file pointer 
 
    string str = memrdr.ReadLine();
    while(str != null) {
      Console.WriteLine(str);
      str = memrdr.ReadLine();
      if(str.CompareTo(".") == 0) break;
    } 
  } 
}

listing 19
// Demonstrate StringReader and StringWriter
 
using System;
using System.IO;
  
class StrRdrDemo {  
  public static void Main() {  
    // Create a StringWriter
    StringWriter strwtr = new StringWriter();
 
    // Write to StringWriter.
    for(int i=0; i < 10; i++)
       strwtr.WriteLine("This is i: " + i);
 
    // Create a StringReader
 
    StringReader strrdr = new StringReader(strwtr.ToString());
 
    // Now, read from StringReader.
    string str = strrdr.ReadLine();
    while(str != null) {
      str = strrdr.ReadLine();
      Console.WriteLine(str);
    } 
 
  } 
}

listing 20
// This program averages a list of numbers entered by the user. 
 
using System;
using System.IO; 
 
class AvgNums { 
  public static void Main() { 
    string str; 
    int n; 
    double sum = 0.0;
    double avg, t; 
     
    Console.Write("How many numbers will you enter: "); 
    str = Console.ReadLine();
    try {
      n = Int32.Parse(str);
    } 
    catch(FormatException exc) {
      Console.WriteLine(exc.Message);
      n = 0;
    }
    catch(OverflowException exc) {
      Console.WriteLine(exc.Message);
      n = 0;
    }
   
    Console.WriteLine("Enter " + n + " values.");
    for(int i=0; i < n ; i++)  { 
      Console.Write(": ");
      str = Console.ReadLine(); 
      try { 
        t = Double.Parse(str); 
      } catch(FormatException exc) { 
        Console.WriteLine(exc.Message); 
        t = 0.0; 
      } 
      catch(OverflowException exc) {
        Console.WriteLine(exc.Message);
        t = 0;
      }
      sum += t; 
    } 
    avg = sum / n;
    Console.WriteLine("Average is " + avg);
  } 
}

listing 1
// A simple delegate example. 
 
using System;
 
// Declare a delegate. 
delegate string StrMod(string str);
 
class DelegateTest {
  // Replaces spaces with hyphens.
  static string replaceSpaces(string a) {
    Console.WriteLine("Replaces spaces with hyphens.");
    return a.Replace(' ', '-');
  } 
 
  // Remove spaces.
  static string removeSpaces(string a) {
    string temp = "";
    int i;
 
    Console.WriteLine("Removing spaces.");
    for(i=0; i < a.Length; i++)
      if(a[i] != ' ') temp += a[i];
 
    return temp;
  } 
 
  // Reverse a string.
  static string reverse(string a) {
    string temp = "";
    int i, j;
 
    Console.WriteLine("Reversing string.");
    for(j=0, i=a.Length-1; i >= 0; i--, j++)
      temp += a[i];
 
    return temp;
  }
    
  public static void Main() { 
    // Construct a delegate.
    StrMod strOp = new StrMod(replaceSpaces);
    string str;
 
    // Call methods through the delegate.
    str = strOp("This is a test.");
    Console.WriteLine("Resulting string: " + str);
    Console.WriteLine();
     
    strOp = new StrMod(removeSpaces);
    str = strOp("This is a test.");
    Console.WriteLine("Resulting string: " + str);
    Console.WriteLine();
 
    strOp = new StrMod(reverse);
    str = strOp("This is a test.");
    Console.WriteLine("Resulting string: " + str);
  }
}

listing 2
public static void Main() { 
  // Construct a delegate using method group conversion.
  StrMod strOp = replaceSpaces; // use method group conversion
  string str;
 
  // Call methods through the delegate.
  str = strOp("This is a test.");
  Console.WriteLine("Resulting string: " + str);
  Console.WriteLine();
     
  strOp = removeSpaces; // use method group conversion
  str = strOp("This is a test.");
  Console.WriteLine("Resulting string: " + str);
  Console.WriteLine();
 
  strOp = reverse; // use method group converison
  str = strOp("This is a test.");
  Console.WriteLine("Resulting string: " + str);
}

listing 3
// Delegates can refer to instance methods, too.
 
using System;
 
// Declare a delegate. 
delegate string StrMod(string str);
 
class StringOps {
  // Replaces spaces with hyphens.
  public string replaceSpaces(string a) {
    Console.WriteLine("Replaces spaces with hyphens.");
    return a.Replace(' ', '-');
  } 
 
  // Remove spaces.
  public string removeSpaces(string a) {
    string temp = "";
    int i;
 
    Console.WriteLine("Removing spaces.");
    for(i=0; i < a.Length; i++)
      if(a[i] != ' ') temp += a[i];
 
    return temp;
  } 
 
  // Reverse a string.
  public string reverse(string a) {
    string temp = "";
    int i, j;
 
    Console.WriteLine("Reversing string.");
    for(j=0, i=a.Length-1; i >= 0; i--, j++)
      temp += a[i];
 
    return temp;
  }
}
 
class DelegateTest {  
  public static void Main() { 
    StringOps so = new StringOps(); // create an instance of StringOps
 
    // Initialize a delegate.
    StrMod strOp = so.replaceSpaces;
    string str;
 
    // Call methods through delegates.
    str = strOp("This is a test.");
    Console.WriteLine("Resulting string: " + str);
    Console.WriteLine();
     
    strOp = so.removeSpaces;
    str = strOp("This is a test.");
    Console.WriteLine("Resulting string: " + str);
    Console.WriteLine();
 
    strOp = so.reverse;
    str = strOp("This is a test.");
    Console.WriteLine("Resulting string: " + str);
  }
}

listing 4
// Demonstrate multicasting. 
 
using System;
 
// Declare a delegate. 
delegate void StrMod(ref string str);
 
class MultiCastDemo {
  // Replaces spaces with hyphens.
  static void replaceSpaces(ref string a) {
    Console.WriteLine("Replaces spaces with hyphens.");
    a = a.Replace(' ', '-');
  } 
 
  // Remove spaces.
  static void removeSpaces(ref string a) {
    string temp = "";
    int i;
 
    Console.WriteLine("Removing spaces.");
    for(i=0; i < a.Length; i++)
      if(a[i] != ' ') temp += a[i];
 
    a = temp;
  } 
 
  // Reverse a string.
  static void reverse(ref string a) {
    string temp = "";
    int i, j;
 
    Console.WriteLine("Reversing string.");
    for(j=0, i=a.Length-1; i >= 0; i--, j++)
      temp += a[i];
 
    a = temp;
  }
    
  public static void Main() { 
    // Construct delegates.
    StrMod strOp;
    StrMod replaceSp = replaceSpaces;
    StrMod removeSp = removeSpaces;
    StrMod reverseStr = reverse;
    string str = "This is a test";
 
    // Set up multicast.
    strOp = replaceSp;
    strOp += reverseStr;
 
    // Call multicast.
    strOp(ref str);
    Console.WriteLine("Resulting string: " + str);
    Console.WriteLine();
    
    // Remove replace and add remove.
    strOp -= replaceSp;
    strOp += removeSp;
 
    str = "This is a test."; // reset string
 
    // Call multicast.
    strOp(ref str);
    Console.WriteLine("Resulting string: " + str);
    Console.WriteLine();
  }
}

listing 5
// Demonstrate an anonymous method.
  
using System; 
 
// Declare a delegate.  
delegate void CountIt(); 
 
class AnonMethDemo { 
 
  public static void Main() {  
 
    // Here, the code for counting is passed
    // as an anonymous method.    
     CountIt count = delegate { 
        // This is the block of code passed to the delegate.
      for(int i=0; i <= 5; i++) 
        Console.WriteLine(i);
    }; // notice the semicolon
 
    count(); 
  }
}

listing 6
// Demonstrate an anonymous method that takes an argument.
  
using System; 
 
// Notice that CountIt now has a parameter.
delegate void CountIt(int end); 
 
class AnonMethDemo2 { 
 
  public static void Main() {  
 
    // Here, the ending value for the count
    // is passed to the anonymous method.
    CountIt count = delegate (int end) {
      for(int i=0; i <= end; i++) 
        Console.WriteLine(i);
    };
 
    count(3);
    Console.WriteLine();
    count(5); 
  }
}

listing 7
// Demonstrate an anonymous method that returns a value.
  
using System; 
 
// This delegate returns a value.
delegate int CountIt(int end); 
 
class AnonMethDemo3 { 
 
  public static void Main() {  
    int result;
 
    // Here, the ending value for the count
    // is passed to the anonymous method.  
    // A summation of the count is returned.
    CountIt count = delegate (int end) {
      int sum = 0;
 
      for(int i=0; i <= end; i++) {
        Console.WriteLine(i);
        sum += i;
      }
      return sum; // return a value from an anonymous method
    };
 
    result = count(3);
    Console.WriteLine("Summation of 3 is " + result);
    Console.WriteLine();
 
    result = count(5); 
    Console.WriteLine("Summation of 5 is " + result);
  }
}

listing 8
// Demonstrate a captured variable.
  
using System; 
 
// This delegate returns int and takes an int argument.
delegate int CountIt(int end); 
 
class VarCapture { 
 
  static CountIt counter() {
    int sum = 0;
 
    // Here, a summation of the count is stored
    // in the captured variable sum.
    CountIt ctObj = delegate (int end) {
      for(int i=0; i <= end; i++) {
        Console.WriteLine(i);
        sum += i;
      }
      return sum;
    };
    return ctObj;
  }
 
  public static void Main() {  
    // Get a counter
    CountIt count = counter();
 
    int result; 
 
    result = count(3);
    Console.WriteLine("Summation of 3 is " + result);
    Console.WriteLine();
 
    result = count(5); 
    Console.WriteLine("Summation of 5 is " + result);
  }
}

listing 9
// Demonstrate covariance and contravariance.
  
using System; 
 
class X {
  public int val;
}
 
// Y is derived from X.
class Y : X { }
 
// This delegate returns X and takes a Y argument.
delegate X ChangeIt(Y obj); 
 
class CoContraVariance { 
 
  // This method returns X and has an X parameter.
  static X incrA(X obj) {
    X temp = new X();
    temp.val = obj.val + 1;
    return temp;
  }
 
  // This method returns Y and has an Y parameter.
  static Y incrB(Y obj) {
    Y temp = new Y();
    temp.val = obj.val + 1;
    return temp;
  }
 
  public static void Main() {  
    Y Yob = new Y();
 
    // In this case, the parameter to incrA
    // is X and the parameter to ChangeIt is Y.
    // Because of contravariance, the following
    // line is OK.
    ChangeIt change = incrA;
 
    X Xob = change(Yob);
 
    Console.WriteLine("Xob: " + Xob.val);
 
    // In the next case, the return type of
    // incrB is Y and the return type of 
    // ChangeIt is X. Because of covariance,
    // the following line is OK.
    change = incrB;
 
    Yob = (Y) change(Yob);
 
    Console.WriteLine("Yob: " + Yob.val);
  }
}

listing 10
// A very simple event demonstration.
 
using System;
 
// Declare a delegate for an event. 
delegate void MyEventHandler();
 
// Declare an event class.
class MyEvent {
  public event MyEventHandler SomeEvent;
 
  // This is called to fire the event.
  public void OnSomeEvent() {
    if(SomeEvent != null)
      SomeEvent();
  }
}
 
class EventDemo {
  // An event handler.
  static void handler() {
    Console.WriteLine("Event occurred");
  }
 
  public static void Main() { 
    MyEvent evt = new MyEvent();
 
    // Add handler() to the event list.
    evt.SomeEvent += handler;
 
    // Fire the event.
    evt.OnSomeEvent();
  }
}

listing 11
// An event multicast demonstration.
 
using System;
 
// Declare a delegate for an event. 
delegate void MyEventHandler();
 
// Declare an event class.
class MyEvent {
  public event MyEventHandler SomeEvent;
 
  // This is called to fire the event.
  public void OnSomeEvent() {
    if(SomeEvent != null)
      SomeEvent();
  }
}
 
class X {
  public void Xhandler() {
    Console.WriteLine("Event received by X object");
  }
}
 
class Y {
  public void Yhandler() {
    Console.WriteLine("Event received by Y object");
  }
}
 
class EventDemo2 {
  static void handler() {
    Console.WriteLine("Event received by EventDemo");
  }
 
  public static void Main() { 
    MyEvent evt = new MyEvent();
    X xOb = new X();
    Y yOb = new Y();
 
    // Add handlers to the event list.
    evt.SomeEvent += handler;
    evt.SomeEvent += xOb.Xhandler;
    evt.SomeEvent += yOb.Yhandler;
 
    // Fire the event.
    evt.OnSomeEvent();
    Console.WriteLine();
 
    // Remove a handler.
    evt.SomeEvent -= xOb.Xhandler;
    evt.OnSomeEvent();
  }
}

listing 12
/* Individual objects receive notifications when instance
   event handlers are used. */
 
using System;
 
// Declare a delegate for an event. 
delegate void MyEventHandler();
 
// Declare an event class.
class MyEvent {
  public event MyEventHandler SomeEvent;
 
  // This is called to fire the event.
  public void OnSomeEvent() {
    if(SomeEvent != null)
      SomeEvent();
  }
}
 
class X {
  int id;
 
  public X(int x) { id = x; }
 
  // This is an instance method that will be used as an event handler.
  public void Xhandler() {
    Console.WriteLine("Event received by object " + id);
  }
}
 
class EventDemo3 {
  public static void Main() { 
    MyEvent evt = new MyEvent();
    X o1 = new X(1);
    X o2 = new X(2);
    X o3 = new X(3);
 
    evt.SomeEvent += o1.Xhandler;
    evt.SomeEvent += o2.Xhandler;
    evt.SomeEvent += o3.Xhandler;
 
    // Fire the event.
    evt.OnSomeEvent();
  }
}

listing 13
/* A class receives the notification when 
   a static method is used as an event handler. */
 
using System;
 
// Declare a delegate for an event. 
delegate void MyEventHandler();
 
// Declare an event class.
class MyEvent {
  public event MyEventHandler SomeEvent;
 
  // This is called to fire the event.
  public void OnSomeEvent() {
    if(SomeEvent != null)
      SomeEvent();
  }
}
 
class X {
 
  /* This is a static method that will be used as
     an event handler. */
  public static void Xhandler() {
    Console.WriteLine("Event received by class.");
  }
}
 
class EventDemo4 {
  public static void Main() { 
    MyEvent evt = new MyEvent();
 
    evt.SomeEvent += X.Xhandler;
 
    // Fire the event.
    evt.OnSomeEvent();
  }
}

listing 14
// Create a custom means of managing the event invocation list.
  
using System; 
 
// Declare a delegate for an event.  
delegate void MyEventHandler(); 
 
// Declare an event class that holds up to 3 events.
class MyEvent { 
  MyEventHandler[] evnt = new MyEventHandler[3];
 
  public event MyEventHandler SomeEvent {
    // Add an event to the list.
    add {
      int i;
 
      for(i=0; i < 3; i++)
        if(evnt[i] == null) {
          evnt[i] = value; 
          break;
        }
      if (i == 3) Console.WriteLine("Event list full.");
    }
 
    // Remove an event from the list.
    remove {
      int i;
 
      for(i=0; i < 3; i++)
        if(evnt[i] == value) {
          evnt[i] = null;
          break;
        }
      if (i == 3) Console.WriteLine("Event handler not found.");
    }
  } 
 
  // This is called to fire the events. 
  public void OnSomeEvent() { 
      for(int i=0; i < 3; i++)
        if(evnt[i] != null) evnt[i](); 
  } 
 

 
// Create some classes that use MyEventHandler.
class W {
  public void Whandler() { 
    Console.WriteLine("Event received by W object"); 
  } 

 
class X {
  public void Xhandler() { 
    Console.WriteLine("Event received by X object"); 
  } 

 
class Y { 
  public void Yhandler() { 
    Console.WriteLine("Event received by Y object"); 
  } 

 
class Z { 
  public void Zhandler() { 
    Console.WriteLine("Event received by Z object"); 
  } 

 
class EventDemo5 { 
  public static void Main() {  
    MyEvent evt = new MyEvent(); 
    W wOb = new W(); 
    X xOb = new X(); 
    Y yOb = new Y(); 
    Z zOb = new Z();
 
    // Add handlers to the event list.
    Console.WriteLine("Adding events.");
    evt.SomeEvent += wOb.Whandler; 
    evt.SomeEvent += xOb.Xhandler; 
    evt.SomeEvent += yOb.Yhandler; 
 
    // Can't store this one -- full.
    evt.SomeEvent += zOb.Zhandler; 
    Console.WriteLine();
 
    // Fire the events. 
    evt.OnSomeEvent(); 
    Console.WriteLine(); 
 
    // Remove a handler.
    Console.WriteLine("Remove xOb.Xhandler.");
    evt.SomeEvent -= xOb.Xhandler; 
    evt.OnSomeEvent(); 
 
    Console.WriteLine();
 
    // Try to remove it again.
    Console.WriteLine("Try to remove xOb.Xhandler again.");
    evt.SomeEvent -= xOb.Xhandler; 
    evt.OnSomeEvent(); 
 
    Console.WriteLine();
 
    // Now, add Zhandler.
    Console.WriteLine("Add zOb.Zhandler.");
    evt.SomeEvent += zOb.Zhandler;
    evt.OnSomeEvent(); 
 
  } 
}

listing 15
// A .NET-compatible event.
 
using System;
 
// Derive a class from EventArgs.
class MyEventArgs : EventArgs {
  public int eventnum;
}
 
// Declare a delegate for an event. 
delegate void MyEventHandler(object source, MyEventArgs arg);
 
// Declare an event class.
class MyEvent {
  static int count = 0;
 
  public event MyEventHandler SomeEvent;
 
  // This fires SomeEvent.
  public void OnSomeEvent() {
    MyEventArgs arg = new MyEventArgs();
 
    if(SomeEvent != null) {
      arg.eventnum = count++;
      SomeEvent(this, arg);
    }
  }
}
 
class X {
  public void handler(object source, MyEventArgs arg) {
    Console.WriteLine("Event " + arg.eventnum +
                      " received by an X object.");
    Console.WriteLine("Source is " + source);
    Console.WriteLine();
  }
}
 
class Y { 
  public void handler(object source, MyEventArgs arg) {
    Console.WriteLine("Event " + arg.eventnum +
                      " received by a Y object.");
    Console.WriteLine("Source is " + source);
    Console.WriteLine();
  }
}
 
class EventDemo6 {
  public static void Main() { 
    X ob1 = new X();
    Y ob2 = new Y();
    MyEvent evt = new MyEvent();
 
    // Add handler() to the event list.
    evt.SomeEvent += ob1.handler;
    evt.SomeEvent += ob2.handler;
 
    // Fire the event.
    evt.OnSomeEvent();
    evt.OnSomeEvent();
  }
}

listing 16
// Use the built-in EventHandler delegate.
 
using System;
 
// Declare an event class.
class MyEvent {
  public event EventHandler SomeEvent; // uses EventHandler delegate
 
  // This is called to fire SomeEvent.
  public void OnSomeEvent() {
    if(SomeEvent != null)
      SomeEvent(this, EventArgs.Empty);
  }
}
 
class EventDemo {
  static void handler(object source, EventArgs arg) {
    Console.WriteLine("Event occurred");
    Console.WriteLine("Source is " + source);
  }
 
  public static void Main() { 
    MyEvent evt = new MyEvent();
 
    // Add handler() to the event list.
    evt.SomeEvent += handler;
 
    // Fire the event.
    evt.OnSomeEvent();
  }
}

listing 17
// Use an anonymous method as an event handler.  
using System; 
 
// Declare a delegate for an event.  
delegate void MyEventHandler(); 
 
// Declare an event class. 
class MyEvent { 
  public event MyEventHandler SomeEvent; 
 
  // This is called to fire the event. 
  public void OnSomeEvent() { 
    if(SomeEvent != null) 
      SomeEvent(); 
  } 

 
class AnonMethHandler { 
  public static void Main() {  
    MyEvent evt = new MyEvent(); 
 
    // Use an anonymous method as an event handler.
    evt.SomeEvent += delegate  { 
      // This is the event handler.
      Console.WriteLine("Event received."); 
    };
 
    // Fire the event twice. 
    evt.OnSomeEvent(); 
    evt.OnSomeEvent(); 
  } 
}

listing 18
// A keypress event example. 
  
using System; 
 
// Derive a custom EventArgs class that holds the key. 
class KeyEventArgs : EventArgs { 
  public char ch; 

 
// Declare a delegate for an event.  
delegate void KeyHandler(object source, KeyEventArgs arg); 
 
// Declare a keypress event class. 
class KeyEvent { 
  public event KeyHandler KeyPress; 
 
  // This is called when a key is pressed. 
  public void OnKeyPress(char key) { 
    KeyEventArgs k = new KeyEventArgs(); 
   
    if(KeyPress != null) { 
      k.ch = key; 
      KeyPress(this, k); 
    } 
  } 

 
// Demonstrate KeyEvent. 
class KeyEventDemo { 
  public static void Main() {  
    KeyEvent kevt = new KeyEvent(); 
    ConsoleKeyInfo key;
    int count = 0;
 
    // Use anonymous method to display the keypress. 
    kevt.KeyPress += delegate(object source, KeyEventArgs arg) { 
      Console.WriteLine(" Received keystroke: " + arg.ch); 
    }; 
 
    // Use an anonymous method to count keypresses.
    kevt.KeyPress += delegate (object source, KeyEventArgs arg) { 
      count++; // count is an outer variable
    }; 
 
    Console.WriteLine("Enter some characters. " + 
                      "Enter a period to stop."); 
    do { 
      key = Console.ReadKey();
      kevt.OnKeyPress(key.KeyChar); 
    } while(key.KeyChar != '.'); 
 
    Console.WriteLine(count + " keys pressed."); 
  } 
}


listing 1
// Declare a namespace for counters.
 
namespace Counter {
  // A simple countdown counter.
  class CountDown {
    int val;
 
    public CountDown(int n) {
      val = n;
   }
 
    public void reset(int n) {
      val = n;
    }
 
    public int count() {
      if(val > 0) return val--;
      else return 0;
    }
  }
}

listing 2
// Demonstrate a namespace.
 
using System;
 
// Declare a namespace for counters.
namespace Counter {
  // A simple countdown counter.
  class CountDown {
    int val;
 
    public CountDown(int n) { val = n; }
 
    public void reset(int n) {
      val = n;
    }
 
    public int count() {
      if(val > 0) return val--;
      else return 0;
    }
  }
}
 
class NSDemo {
  public static void Main() {
    // Notice how CountDown is qualified by Counter.
    Counter.CountDown cd1 = new Counter.CountDown(10);
    int i;
 
    do {
      i = cd1.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
 
    // Agian, notice how CountDown is qualified by Counter.
    Counter.CountDown cd2 = new Counter.CountDown(20);
 
    do {
      i = cd2.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
 
    cd2.reset(4);
    do {
      i = cd2.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
  }
}

listing 3
// Namespaces prevent name conflicts.
 
using System; 
 
// Declare a namespace for counters. 
namespace Counter { 
  // A simple countdown counter. 
  class CountDown { 
    int val; 
 
    public CountDown(int n) {
      val = n;
    } 
 
    public void reset(int n) { 
      val = n; 
    } 
 
    public int count() { 
      if(val > 0) return val--; 
      else return 0; 
    } 
  } 

 
// Declare another namespace. 
namespace Counter2 { 
  /* This CountDown is in the default namespace and 
     does not conflict with the one in Counter. */
  class CountDown {
    public void count() {
      Console.WriteLine("This is count() in the " +
                        "Counter2 namespace.");
    }
  }
}
 
class NSDemo2 { 
  public static void Main() { 
    // This is CountDown in the Counter namespace.
    Counter.CountDown cd1 = new Counter.CountDown(10); 
 
    // This is CountDown in the default namespace.
    Counter2.CountDown cd2 = new Counter2.CountDown();
 
    int i; 
 
    do { 
      i = cd1.count(); 
      Console.Write(i + " "); 
    } while(i > 0); 
    Console.WriteLine(); 
 
    cd2.count();
  } 
}

listing 4
// Demonstrate the using directive.
 
using System;
 
// Bring Counter into view.
using Counter;
 
// Declare a namespace for counters.
namespace Counter {
  // A simple countdown counter.
  class CountDown {
    int val;
 
    public CountDown(int n) {
      val = n;
    }
 
    public void reset(int n) {
      val = n;
    }
 
    public int count() {
      if(val > 0) return val--;
      else return 0;
    }
  }
}
 
class NSDemo3 {
  public static void Main() {
    // now, CountDown can be used directly.
    CountDown cd1 = new CountDown(10);
    int i;
 
    do {
      i = cd1.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
 
    CountDown cd2 = new CountDown(20);
 
    do {
      i = cd2.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
 
    cd2.reset(4);
    do {
      i = cd2.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
  }
}

listing 5
// Demonstrate a using alias.
 
using System;
 
// Create an alias for Counter.CountDown.
using Count = Counter.CountDown;
 
// Declare a namespace for counters.
namespace Counter {
  // A simple countdown counter.
  class CountDown {
    int val;
 
    public CountDown(int n) {
      val = n;
    }
 
    public void reset(int n) {
      val = n;
    }
 
    public int count() {
      if(val > 0) return val--;
      else return 0;
    }
  }
}
 
class NSDemo4 {
  public static void Main() {
    // Here, Count is used as a name for Counter.CountDown.
    Count cd1 = new Count(10);
    int i;
 
    do {
      i = cd1.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
 
    Count cd2 = new Count(20);
 
    do {
      i = cd2.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
 
    cd2.reset(4);
    do {
      i = cd2.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
  }
}

listing 6
// Namespaces are additive.
 
using System;
 
// Bring Counter into view.
using Counter;
 
// Here is one Counter namespace.
namespace Counter {
  // A simple countdown counter.
  class CountDown {
    int val;
 
    public CountDown(int n) {
      val = n;
    }
 
    public void reset(int n) {
      val = n;
    }
 
    public int count() {
      if(val > 0) return val--;
      else return 0;
    }
  }
}
 
// Here is another Counter namespace.
namespace Counter {
  // A simple count-up counter.
  class CountUp {
    int val;
    int target;
 
    public int Target {
      get{
        return target;
      }
    }
 
    public CountUp(int n) {
      target = n;
      val = 0;
    }
 
    public void reset(int n) {
      target = n;
      val = 0;
    }
 
    public int count() {
      if(val < target) return val++;
      else return target;
    }
  }
}
 
class NSDemo5 {
  public static void Main() {
    CountDown cd = new CountDown(10);
    CountUp cu = new CountUp(8);
    int i;
 
    do {
      i = cd.count();
      Console.Write(i + " ");
    } while(i > 0);
    Console.WriteLine();
 
    do {
      i = cu.count();
      Console.Write(i + " ");
    } while(i < cu.Target);
 
  }
}

listing 7
// Namespaces can be nested.
 
using System;
 
namespace NS1 {
  class ClassA {
     public ClassA() {
       Console.WriteLine("constructing ClassA");
    }
  }
  namespace NS2 { // a nested namespace
    class ClassB {
       public ClassB() {
         Console.WriteLine("constructing ClassB");
      }
    }
  }
}
 
class NestedNSDemo {
  public static void Main() {
    NS1.ClassA a = new NS1.ClassA();
 
 // NS2.ClassB b = new NS2.ClassB(); // Error!!! NS2 is not in view
 
    NS1.NS2.ClassB b = new NS1.NS2.ClassB(); // this is right
  }
}

listing 8
// Demonstrate why the :: qualifier is needed.
// 
// This program will not compile.
 
using System; 
 
// Use both the Counter and AnotherCounter namespace
using Counter;
using AnotherCounter;
 
// Declare a namespace for counters. 
namespace Counter { 
  // A simple countdown counter. 
  class CountDown { 
    int val; 
 
    public CountDown(int n) { 
      val = n; 
    } 
 
    // ... 
  } 

 
// Declare another namespaces for counters.
namespace AnotherCounter { 
  // Declare another class called CountDown, which 
  // is in the global namespace.
  class CountDown {
    int val; 
 
    public CountDown(int n) { 
      val = n; 
    }
 
    // ...  
  }
}
 
class WhyAliasQualifier { 
  public static void Main() { 
    int i; 
 
    // The following line is inherently ambiguous!
    // Does it refer to CountDown in Counter or
    // to CountDown in AnotherCounter?
    CountDown cd1 = new CountDown(10); // Error! ! !
 
    // ...
  } 
}

listing 9
// Demonstrate the :: qualifier. 
 
using System; 
 
using Counter;
using AnotherCounter;
 
// Give Counter an alias called Ctr.
using Ctr = Counter; 
 
// Declare a namespace for counters. 
namespace Counter { 
  // A simple countdown counter. 
  class CountDown { 
    int val; 
 
    public CountDown(int n) { 
      val = n; 
    } 
 
    // ...
  } 

 
// Another counter namespace.
namespace AnotherCounter { 
  // Declare another class called CountDown, which 
  // is in the global namespace.
  class CountDown {
    int val; 
 
    public CountDown(int n) { 
      val = n; 
    }
 
    // ...  
  }
}
 
class AliasQualifierDemo { 
  public static void Main() { 
 
    // Here, the :: operator to resolves
    // tells the compiler to use the CountDown
    // that is in the Counter namespace.
    Ctr::CountDown cd1 = new Ctr::CountDown(10); 
 
    // ...
  } 
}

listing 10
// Use the global alias.
 
using System; 
 
// Give Counter an alias called Ctr.
using Ctr = Counter; 
 
// Declare a namespace for counters. 
namespace Counter { 
  // A simple countdown counter. 
  class CountDown { 
    int val; 
 
    public CountDown(int n) { 
      val = n; 
    } 
 
    // ...
  } 

 
// Declare another class called CountDown, which 
// is in the global namespace. 
class CountDown {
  int val; 
 
  public CountDown(int n) { 
    val = n; 
  } 
 
  // ... 
}
 
class GlobalAliasQualifierDemo { 
  public static void Main() { 
 
    // Here, the :: qualifier tells the compiler
    // to use the CountDown to use the Counter namespace.
    Ctr::CountDown cd1 = new Ctr::CountDown(10); 
 
    // Next, create CountDown object from global namespace.
    global::CountDown cd2 = new global::CountDown(10); 
 
    // ... 
  } 
}

listing 11
// Demonstrate #if, #endif, and #define.
 
#define EXPERIMENTAL
 
using System;
 
class Test {
  public static void Main() {
    
    #if EXPERIMENTAL
      Console.WriteLine("Compiled for experimental version.");
    #endif
  
    Console.WriteLine("This is in all versions.");
  }
}

listing 12
// Use a symbol expression.
 
#define EXPERIMENTAL
#define TRIAL
 
using System;
 
class Test {
  public static void Main() {
    
    #if EXPERIMENTAL
      Console.WriteLine("Compiled for experimental version.");
    #endif
 
    #if EXPERIMENTAL && TRIAL
       Console.Error.WriteLine("Testing experimental trial version.");
    #endif
  
    Console.WriteLine("This is in all versions.");
  }
}

listing 13
// Demonstrate #else.
 
#define EXPERIMENTAL
 
using System;
 
class Test {
  public static void Main() {
    
    #if EXPERIMENTAL
      Console.WriteLine("Compiled for experimental version.");
    #else
      Console.WriteLine("Compiled for release.");
    #endif
 
    #if EXPERIMENTAL && TRIAL
       Console.Error.WriteLine("Testing experimental trial version.");
    #else
       Console.Error.WriteLine("Not experimental trial version.");
    #endif
  
    Console.WriteLine("This is in all versions.");
  }
}

listing 14
// Demonstrate #elif.
 
#define RELEASE
 
using System;
 
class Test {
  public static void Main() {
    
    #if EXPERIMENTAL
      Console.WriteLine("Compiled for experimental version.");
    #elif RELEASE
      Console.WriteLine("Compiled for release.");
    #else
      Console.WriteLine("Compiled for internal testing.");
    #endif
 
    #if TRIAL && !RELEASE
       Console.WriteLine("Trial version.");
    #endif
  
    Console.WriteLine("This is in all versions.");
  }
}

listing 15
// Use internal.
 
using System;
 
class InternalTest {
  internal int x;
}
 
class InternalDemo {
  public static void Main() {
    InternalTest ob = new InternalTest();
 
    ob.x = 10; // can access -- in same file
 
    Console.WriteLine("Here is ob.x: " + ob.x);
 
  }
}

listing 1
// Demonstrate is.
 
using System;
 
class A {}
class B : A {}
 
class UseIs {
  public static void Main() {
    A a = new A();
    B b = new B();
 
    if(a is A) Console.WriteLine("a is an A");
    if(b is A) 
      Console.WriteLine("b is an A because it is derived from A");
    if(a is B) 
      Console.WriteLine("This won't display -- a not derived from B");
 
    if(b is B) Console.WriteLine("B is a B");
    if(a is object) Console.WriteLine("a is an object");
  }
}

listing 2
// Use is to avoid an invalid cast.
 
using System;
 
class A {}
class B : A {}
 
class CheckCast {
  public static void Main() {
    A a = new A();
    B b = new B();
 
    // Check to see if a can be cast to B.
    if(a is B)  // if so, do the cast
      b = (B) a;
    else // if not, skip the cast
      b = null;
 
    if(b==null) 
      Console.WriteLine("Cast b = (B) a is NOT allowed.");
    else
      Console.WriteLine("Cast b = (B) a is allowed");
  }
}

listing 3
// Demonstrate as.
 
using System;
 
class A {}
class B : A {}
 
class CheckCast {
  public static void Main() {
    A a = new A();
    B b = new B();
 
    b = a as B; // cast, if possible
 
    if(b==null) 
      Console.WriteLine("Cast b = (B) a is NOT allowed.");
    else
      Console.WriteLine("Cast b = (B) a is allowed");
  }
}

listing 4
// Demonstrate typeof.
 
using System;
using System.IO;
 
class UseTypeof {
  public static void Main() {
    Type t = typeof(StreamReader);
 
    Console.WriteLine(t.FullName);    
 
    if(t.IsClass) Console.WriteLine("Is a class.");
    if(t.IsAbstract) Console.WriteLine("Is abstract.");
    else Console.WriteLine("Is concrete.");
 
  }
}

listing 5
// Analyze methods using reflection.
 
using System;
using System.Reflection;
 
class MyClass {
  int x;
  int y;
 
  public MyClass(int i, int j) {
    x = i;
    y = j;
  }
 
  public int sum() {
    return x+y;
  }
 
  public bool isBetween(int i) {
    if(x < i && i < y) return true;
    else return false;
  }
 
  public void set(int a, int b) {
    x = a;
    y = b;
  }
 
  public void set(double a, double b) {
    x = (int) a;
    y = (int) b;
  }
 
  public void show() {
    Console.WriteLine(" x: {0}, y: {1}", x, y);
  }
}
 
class ReflectDemo {
  public static void Main() {
    Type t = typeof(MyClass); // get a Type object representing MyClass
 
    Console.WriteLine("Analyzing methods in " + t.Name);    
    Console.WriteLine();
 
    Console.WriteLine("Methods supported: ");
 
    MethodInfo[] mi = t.GetMethods();
 
    // Display methods supported by MyClass.
    foreach(MethodInfo m in mi) {
      // Display return type and name.
      Console.Write("   " + m.ReturnType.Name +
                      " " + m.Name + "(");
 
      // Display parameters.
      ParameterInfo[] pi = m.GetParameters();
 
      for(int i=0; i < pi.Length; i++) {
        Console.Write(pi[i].ParameterType.Name +
                      " " + pi[i].Name);
        if(i+1 < pi.Length) Console.Write(", ");
      }
 
      Console.WriteLine(")");
    
      Console.WriteLine();
    }
  }
}

listing 6
// Invoke methods using reflection.
 
using System;
using System.Reflection;
 
class MyClass {
  int x;
  int y;
 
  public MyClass(int i, int j) {
    x = i;
    y = j;
  }
 
  public int sum() {
    return x+y;
  }
 
  public bool isBetween(int i) {
    if((x < i) && (i < y)) return true;
    else return false;
  }
 
  public void set(int a, int b) {
    Console.Write("Inside set(int, int). ");
    x = a;
    y = b;
    show();
  }
 
  // Overload set.
  public void set(double a, double b) {
    Console.Write("Inside set(double, double). ");
    x = (int) a;
    y = (int) b;
    show();
  }
 
  public void show() {
    Console.WriteLine("Values are x: {0}, y: {1}", x, y);
  }
}
 
class InvokeMethDemo {
  public static void Main() {
    Type t = typeof(MyClass);  
    MyClass reflectOb = new MyClass(10, 20);
    int val;
 
    Console.WriteLine("Invoking methods in " + t.Name);    
    Console.WriteLine();
    MethodInfo[] mi = t.GetMethods();
 
    // Invoke each method.
    foreach(MethodInfo m in mi) {
      // Get the parameters.
      ParameterInfo[] pi = m.GetParameters();
 
      if(m.Name.CompareTo("set")==0 &&
         pi[0].ParameterType == typeof(int)) {
        object[] args = new object[2];
        args[0] = 9;
        args[1] = 18;
        m.Invoke(reflectOb, args);
      }
      else if(m.Name.CompareTo("set")==0 &&
         pi[0].ParameterType == typeof(double)) {
        object[] args = new object[2];
        args[0] = 1.12;
        args[1] = 23.4;
        m.Invoke(reflectOb, args);
      }
      else if(m.Name.CompareTo("sum")==0) {
        val = (int) m.Invoke(reflectOb, null);
        Console.WriteLine("sum is " + val);
      }
      else if(m.Name.CompareTo("isBetween")==0) {
        object[] args = new object[1];
        args[0] = 14;
        if((bool) m.Invoke(reflectOb, args))
          Console.WriteLine("14 is between x and y");
      }
      else if(m.Name.CompareTo("show")==0) {
        m.Invoke(reflectOb, null);
      }
    }
  }
}

listing 7
// Create an object using reflection.
 
using System;
using System.Reflection;
 
class MyClass {
  int x;
  int y;
 
  public MyClass(int i) {
    Console.WriteLine("Constructing MyClass(int, int). ");
    x = y = i; 
  }
 
  public MyClass(int i, int j) {
    Console.WriteLine("Constructing MyClass(int, int). ");
    x = i;
    y = j;
    show();
  }
 
  public int sum() {
    return x+y;
  }
 
  public bool isBetween(int i) {
    if((x < i) && (i < y)) return true;
    else return false;
  }
 
  public void set(int a, int b) {
    Console.Write("Inside set(int, int). ");
    x = a;
    y = b;
    show();
  }
 
  // Overload set.
  public void set(double a, double b) {
    Console.Write("Inside set(double, double). ");
    x = (int) a;
    y = (int) b;
    show();
  }
 
  public void show() {
    Console.WriteLine("Values are x: {0}, y: {1}", x, y);
  }
 
}
 
class InvokeConsDemo {
  public static void Main() {
    Type t = typeof(MyClass);
    int val;
 
    // Get constructor info.
    ConstructorInfo[] ci = t.GetConstructors();
 
    Console.WriteLine("Available constructors: ");
    foreach(ConstructorInfo c in ci) {
      // Display return type and name.
      Console.Write("   " + t.Name + "(");
 
      // Display parameters.
      ParameterInfo[] pi = c.GetParameters();
 
      for(int i=0; i < pi.Length; i++) {
        Console.Write(pi[i].ParameterType.Name +
                      " " + pi[i].Name);
        if(i+1 < pi.Length) Console.Write(", ");
      }
 
      Console.WriteLine(")");
    }
    Console.WriteLine();
 
    // Find matching constructor.
    int x;
 
    for(x=0; x < ci.Length; x++) {
      ParameterInfo[] pi =  ci[x].GetParameters();
      if(pi.Length == 2) break;
    }
 
    if(x == ci.Length) {
      Console.WriteLine("No matching constructor found.");
      return;
    }
    else
      Console.WriteLine("Two-parameter constructor found.\n");
 
    // Construct the object.  
    object[] consargs = new object[2];
    consargs[0] = 10;
    consargs[1] = 20;
    object reflectOb = ci[x].Invoke(consargs);
 
    Console.WriteLine("\nInvoking methods on reflectOb.");
    Console.WriteLine();
    MethodInfo[] mi = t.GetMethods();
 
    // Invoke each method.
    foreach(MethodInfo m in mi) {
      // Get the parameters.
      ParameterInfo[] pi = m.GetParameters();
 
      if(m.Name.CompareTo("set")==0 &&
         pi[0].ParameterType == typeof(int)) {
        // This is set(int, int).
        object[] args = new object[2];
        args[0] = 9;
        args[1] = 18;
        m.Invoke(reflectOb, args);
      }
      else if(m.Name.CompareTo("set")==0 &&
              pi[0].ParameterType == typeof(double)) {
        // This is set(double, double).
        object[] args = new object[2];
        args[0] = 1.12;
        args[1] = 23.4;
        m.Invoke(reflectOb, args);
      }
      else if(m.Name.CompareTo("sum")==0) {
        val = (int) m.Invoke(reflectOb, null);
        Console.WriteLine("sum is " + val);
      }
      else if(m.Name.CompareTo("isBetween")==0) {
        object[] args = new object[1];
        args[0] = 14;
        if((bool) m.Invoke(reflectOb, args))
          Console.WriteLine("14 is between x and y");
      }
      else if(m.Name.CompareTo("show")==0) {
        m.Invoke(reflectOb, null);
      }
    }
  }
}

listing 8
// A file that contains three classes.  Call this file MyClasses.cs.
 
using System;
 
class MyClass {
  int x;
  int y;
 
  public MyClass(int i) {
    Console.WriteLine("Constructing MyClass(int). ");
    x = y = i; 
    show();
  }
 
  public MyClass(int i, int j) {
    Console.WriteLine("Constructing MyClass(int, int). ");
    x = i;
    y = j;
    show();
  }
 
  public int sum() {
    return x+y;
  }
 
  public bool isBetween(int i) {
    if((x < i) && (i < y)) return true;
    else return false;
  }
 
  public void set(int a, int b) {
    Console.Write("Inside set(int, int). ");
    x = a;
    y = b;
    show();
  }
 
  // Overload set.
  public void set(double a, double b) {
    Console.Write("Inside set(double, double). ");
    x = (int) a;
    y = (int) b;
    show();
  }
 
  public void show() {
    Console.WriteLine("Values are x: {0}, y: {1}", x, y);
  }
}
 
class AnotherClass {
  string remark;
 
  public AnotherClass(string str) {
    remark = str;
  }
 
  public void show() {
    Console.WriteLine(remark);
  }
}
 
class Demo {
  public static void Main() {
    Console.WriteLine("This is a placeholder.");
  }
}

listing 9
/* Locate an assembly, determine types, and create 
   an object using reflection. */
 
using System;
using System.Reflection;
 
class ReflectAssemblyDemo {
  public static void Main() {
    int val;
 
    // Load the MyClasses.exe assembly.
    Assembly asm = Assembly.LoadFrom("MyClasses.exe");
 
    // Discover what types MyClasses.exe contains.
    Type[] alltypes = asm.GetTypes();
    foreach(Type temp in alltypes)
      Console.WriteLine("Found: " + temp.Name);
 
    Console.WriteLine();
 
    // Use the first type, which is MyClass in this case.
    Type t = alltypes[0]; // use first class found
    Console.WriteLine("Using: " + t.Name);
 
    // Obtain constructor info.
    ConstructorInfo[] ci = t.GetConstructors();
 
    Console.WriteLine("Available constructors: ");
    foreach(ConstructorInfo c in ci) {
      // Display return type and name.
      Console.Write("   " + t.Name + "(");
 
      // Display parameters.
      ParameterInfo[] pi = c.GetParameters();
 
      for(int i=0; i < pi.Length; i++) {
        Console.Write(pi[i].ParameterType.Name +
                      " " + pi[i].Name);
        if(i+1 < pi.Length) Console.Write(", ");
      }
 
      Console.WriteLine(")");
    }
    Console.WriteLine();
 
    // Find matching constructor.
    int x;
 
    for(x=0; x < ci.Length; x++) {
      ParameterInfo[] pi =  ci[x].GetParameters();
      if(pi.Length == 2) break;
    }
 
    if(x == ci.Length) {
      Console.WriteLine("No matching constructor found.");
      return;
    }
    else
      Console.WriteLine("Two-parameter constructor found.\n");
 
    // Construct the object.  
    object[] consargs = new object[2];
    consargs[0] = 10;
    consargs[1] = 20;
    object reflectOb = ci[x].Invoke(consargs);
 
    Console.WriteLine("\nInvoking methods on reflectOb.");
    Console.WriteLine();
    MethodInfo[] mi = t.GetMethods();
 
    // Invoke each method.
    foreach(MethodInfo m in mi) {
      // Get the parameters.
      ParameterInfo[] pi = m.GetParameters();
 
      if(m.Name.CompareTo("set")==0 &&
         pi[0].ParameterType == typeof(int)) {
        // This is set(int, int).
        object[] args = new object[2];
        args[0] = 9;
        args[1] = 18;
        m.Invoke(reflectOb, args);
      }
      else if(m.Name.CompareTo("set")==0 &&
         pi[0].ParameterType == typeof(double)) {
        // This is set(double, double).
        object[] args = new object[2];
        args[0] = 1.12;
        args[1] = 23.4;
        m.Invoke(reflectOb, args);
      }
      else if(m.Name.CompareTo("sum")==0) {
        val = (int) m.Invoke(reflectOb, null);
        Console.WriteLine("sum is " + val);
      }
      else if(m.Name.CompareTo("isBetween")==0) {
        object[] args = new object[1];
        args[0] = 14;
        if((bool) m.Invoke(reflectOb, args))
          Console.WriteLine("14 is between x and y");
      }
      else if(m.Name.CompareTo("show")==0) {
        m.Invoke(reflectOb, null);
      }
    }
 
  }
}

listing 10
// Utilize MyClass without assuming any prior knowledge.
 
using System;
using System.Reflection;
 
class ReflectAssemblyDemo {
  public static void Main() {
    int val;
    Assembly asm = Assembly.LoadFrom("MyClasses.exe");
 
    Type[] alltypes = asm.GetTypes();
 
    Type t = alltypes[0]; // use first class found
 
    Console.WriteLine("Using: " + t.Name);
 
    ConstructorInfo[] ci = t.GetConstructors();
 
    // Use first constructor found.
    ParameterInfo[] cpi = ci[0].GetParameters();
    object reflectOb;
 
    if(cpi.Length > 0) {
      object[] consargs = new object[cpi.Length];
 
      // initialize args
      for(int n=0; n < cpi.Length; n++)
        consargs[n] = 10 + n * 20;
 
      // construct the object
      reflectOb = ci[0].Invoke(consargs);
    } else
      reflectOb = ci[0].Invoke(null);
    
 
    Console.WriteLine("\nInvoking methods on reflectOb.");
    Console.WriteLine();
 
    // Ignore inherited methods.
    MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly |
                                   BindingFlags.Instance |
                                   BindingFlags.Public) ;
 
    // Invoke each method.
    foreach(MethodInfo m in mi) {
      Console.WriteLine("Calling {0} ", m.Name);
 
      // Get the parameters.
      ParameterInfo[] pi = m.GetParameters();
 
      // Execute methods.
      switch(pi.Length) {
        case 0: // no args
          if(m.ReturnType == typeof(int)) {
            val = (int) m.Invoke(reflectOb, null);
            Console.WriteLine("Result is " + val);
          }
          else if(m.ReturnType == typeof(void)) {
            m.Invoke(reflectOb, null);
          }
          break;
        case 1: // one arg
          if(pi[0].ParameterType == typeof(int)) {
            object[] args = new object[1];
            args[0] = 14;
            if((bool) m.Invoke(reflectOb, args))
              Console.WriteLine("14 is between x and y");
            else
              Console.WriteLine("14 is not between x and y");
          }
          break;
        case 2: // two args
          if((pi[0].ParameterType == typeof(int)) &&
             (pi[1].ParameterType == typeof(int))) {
            object[] args = new object[2];
            args[0] = 9;
            args[1] = 18;
            m.Invoke(reflectOb, args);
          }
          else if((pi[0].ParameterType == typeof(double)) &&
                  (pi[1].ParameterType == typeof(double))) {
            object[] args = new object[2];
            args[0] = 1.12;
            args[1] = 23.4;
            m.Invoke(reflectOb, args);
          }
          break;
      }     
      Console.WriteLine();
    }
 
  }
}

listing 11
[AttributeUsage(AttributeTargets.All)]
public class RemarkAttribute : Attribute {
  string pri_remark; // underlies remark property
 
  public RemarkAttribute(string comment) {
    pri_remark = comment;
  }
 
  public string remark {
    get {
      return pri_remark;
    }
  }
}

listing 12
// A simple attribute example.
 
using System; 
using System.Reflection;
 
[AttributeUsage(AttributeTargets.All)]
public class RemarkAttribute : Attribute {
  string pri_remark; // underlies remark property
 
  public RemarkAttribute(string comment) {
    pri_remark = comment;
  }
 
  public string remark {
    get {
      return pri_remark;
    }
  }

 
[RemarkAttribute("This class uses an attribute.")]
class UseAttrib {
  // ...
}
 
class AttribDemo { 
  public static void Main() { 
    Type t = typeof(UseAttrib);
 
    Console.Write("Attributes in " + t.Name + ": ");
 
    object[] attribs = t.GetCustomAttributes(false); 
    foreach(object o in attribs) {
      Console.WriteLine(o);
    }
 
    Console.Write("Remark: ");
 
    // Retrieve the RemarkAttribute.
    Type tRemAtt = typeof(RemarkAttribute);
    RemarkAttribute ra = (RemarkAttribute)
          Attribute.GetCustomAttribute(t, tRemAtt);
 
    Console.WriteLine(ra.remark);
  } 
}

listing 13
[AttributeUsage(AttributeTargets.All)]
public class RemarkAttribute : Attribute {
  string pri_remark; // underlies remark property
 
  public string supplement; // this is a named parameter
 
  public RemarkAttribute(string comment) {
    pri_remark = comment;
    supplement = "None";
  }
 
  public string remark {
    get {
      return pri_remark;
    }
  }
}

listing 14
// Use a named attribute parameter.
 
using System; 
using System.Reflection;
 
[AttributeUsage(AttributeTargets.All)]
public class RemarkAttribute : Attribute {
  string pri_remark; // underlies remark property
 
  public string supplement; // this is a named parameter
 
  public RemarkAttribute(string comment) {
    pri_remark = comment;
    supplement = "None";
  }
 
  public string remark {
    get {
      return pri_remark;
    }
  }

 
[RemarkAttribute("This class uses an attribute.",
                 supplement = "This is additional info.")]
class UseAttrib {
  // ...
}
 
class NamedParamDemo { 
  public static void Main() { 
    Type t = typeof(UseAttrib);
 
    Console.Write("Attributes in " + t.Name + ": ");
 
    object[] attribs = t.GetCustomAttributes(false); 
    foreach(object o in attribs) {
      Console.WriteLine(o);
    }
 
    // Retrieve the RemarkAttribute.
    Type tRemAtt = typeof(RemarkAttribute);
    RemarkAttribute ra = (RemarkAttribute)
          Attribute.GetCustomAttribute(t, tRemAtt);
 
    Console.Write("Remark: ");
    Console.WriteLine(ra.remark);
 
    Console.Write("Supplement: ");
    Console.WriteLine(ra.supplement);
  } 
}

listing 15
// Use a property as a named attribute parameter.
 
using System; 
using System.Reflection;
 
[AttributeUsage(AttributeTargets.All)]
public class RemarkAttribute : Attribute {
  string pri_remark; // underlies remark property
 
  int pri_priority; // underlies priority property
 
  public string supplement; // this is a named parameter
 
  public RemarkAttribute(string comment) {
    pri_remark = comment;
    supplement = "None";
  }
 
  public string remark {
    get {
      return pri_remark;
    }
  }
 
  // Use a property as a named parameter.
  public int priority {
    get {
      return pri_priority;
    }
    set {
      pri_priority = value;
    }
  }

 
[RemarkAttribute("This class uses an attribute.",
                 supplement = "This is additional info.",
                 priority = 10)]
class UseAttrib {
  // ...
}
 
class NamedParamDemo { 
  public static void Main() { 
    Type t = typeof(UseAttrib);
 
    Console.Write("Attributes in " + t.Name + ": ");
 
    object[] attribs = t.GetCustomAttributes(false); 
    foreach(object o in attribs) {
      Console.WriteLine(o);
    }
 
    // Retrieve the RemarkAttribute.
    Type tRemAtt = typeof(RemarkAttribute);
    RemarkAttribute ra = (RemarkAttribute)
          Attribute.GetCustomAttribute(t, tRemAtt);
 
    Console.Write("Remark: ");
    Console.WriteLine(ra.remark);
 
    Console.Write("Supplement: ");
    Console.WriteLine(ra.supplement);
 
    Console.WriteLine("Priority: " + ra.priority);
  } 
}

listing 16
// Demonstrate the Conditional attribute.
 
#define TRIAL
 
using System;
using System.Diagnostics;
 
class Test {
 
  [Conditional("TRIAL")] 
  void trial() {
    Console.WriteLine("Trial version, not for distribution.");
  }
 
  [Conditional("RELEASE")] 
  void release() {
    Console.WriteLine("Final release version.");
  }
 
  public static void Main() {
    Test t = new Test();
 
    t.trial(); // call only if TRIAL is defined
    t.release(); // called only if RELEASE is defined
  }
}

listing 17
// Demonstrate the Obsolete attribute.
 
using System;
 
class Test {
 
  [Obsolete("Use myMeth2, instead.")] 
  static int myMeth(int a, int b) {
    return a / b;
  }
 
  // Improved version of myMeth.
  static int myMeth2(int a, int b) {
    return b == 0 ? 0 : a /b;
  }
 
  public static void Main() {
   // warning displayed for this
    Console.WriteLine("4 / 3 is " + Test.myMeth(4, 3));
 
   // no warning here
    Console.WriteLine("4 / 3 is " + Test.myMeth2(4, 3)); 
  }
}

listing 1
// A simple generic class. 
 
using System;
 
// In the following Gen class, T is a type
// parameter that will be replaced by a real
// type when an object of type Gen is created.
class Gen<T> {
  T ob; // declare an object of type T
  
  // Notice that this constructor has a parameter of type T.
  public Gen(T o) {
    ob = o;
  }
 
  // Return ob, which is of type T.
  public T getob() {
    return ob;
  }
 
  // Show type of T.
  public void showType() {
    Console.WriteLine("Type of T is " + typeof(T));
  }
}
 
// Demonstrate the generic class.
class GenericsDemo {
  public static void Main() {
    // Create a Gen reference for int.
    Gen<int> iOb; 
 
    // Create a Gen<int> object and assign its
    // reference to iOb.
    iOb = new Gen<int>(102);
 
    // Show the type of data used by iOb.
    iOb.showType();
 
    // Get the value in iOb.
    int v = iOb.getob();
    Console.WriteLine("value: " + v);
 
    Console.WriteLine();
 
    // Create a Gen object for strings.
    Gen<string> strOb = new Gen<string>("Generics add power.");
 
    // Show the type of data stored in strOb.
    strOb.showType();
 
    // Get the value in strOb.
    string str = strOb.getob();
    Console.WriteLine("value: " + str);
  }
}

listing 2
// NonGen is functionally equivalent to Gen
// but does not use generics. 
 
using System;
 
class NonGen { 
  object ob; // ob is now of type object
   
  // Pass the constructor a reference of  
  // type object.
  public NonGen(object o) { 
    ob = o; 
  } 
 
  // Return type object.
  public object getob() { 
    return ob; 
  } 
 
  // Show type of ob. 
  public void showType() { 
    Console.WriteLine("Type of ob is " + ob.GetType());
  } 

 
// Demonstrate the non-generic class. 
class NonGenDemo { 
  public static void Main() { 
    NonGen iOb;  
 
    // Create NonGen object.
    iOb = new NonGen(102); 
 
    // Show the type of data stored in iOb.
    iOb.showType();
 
    // Get the value in iOb.
    // This time, a cast is necessary.
    int v = (int) iOb.getob(); 
    Console.WriteLine("value: " + v); 
 
    Console.WriteLine(); 
 
    // Create another NonGen object and 
    // store a string in it.
    NonGen strOb = new NonGen("Non-Generics Test"); 
 
    // Show the type of data stored strOb.
    strOb.showType();
 
    // Get the value of strOb.
    // Again, notice that a cast is necessary. 
    String str = (string) strOb.getob(); 
    Console.WriteLine("value: " + str); 
 
    // This compiles, but is conceptually wrong!
    iOb = strOb;
 
    // The following line results in a run-time exception.
    // v = (int) iOb.getob(); // run-time error!
  } 
}

listing 3
// A simple generic class with two type
// parameters: T and V.
 
using System;
 
class TwoGen<T, V> {
  T ob1;
  V ob2;
  
  // Notice that this construtor has parameters
  // of type T and V.
  public TwoGen(T o1, V o2) {
    ob1 = o1;
    ob2 = o2;
  }
 
  // Show types of T and V.
  public void showTypes() {
    Console.WriteLine("Type of T is " + typeof(T));
    Console.WriteLine("Type of V is " + typeof(V));
  }
 
  public T getob1() {
    return ob1;
  }
 
  public V getob2() {
    return ob2;
  }
}
 
// Demonstrate two generic type parameters.
class SimpGen {
  public static void Main() {
 
    TwoGen<int, string> tgObj =
      new TwoGen<int, string>(119, "Alpha Beta Gamma");
 
    // Show the types.
    tgObj.showTypes();
 
    // Obtain and show values.
    int v = tgObj.getob1();
    Console.WriteLine("value: " + v);
 
    string str = tgObj.getob2();
    Console.WriteLine("value: " + str);
  }
}

listing 4
// A simple demonstration of a base class constraint.
 
using System;
 
class A {
  public void hello() {
    Console.WriteLine("Hello");
  }
}
 
// Class B inherits A.
class B : A { }
 
// Class C does not inherit A.
class C { }
 
// Because of the base class constraint, all type arguments
// passed to Test must have A as a base class.
class Test<T> where T : A {
  T obj;
 
  public Test(T o) {
    obj = o;
  }
 
  public void sayHello() {
    // OK to call hello() because it's declared
    // by the base class A.
    obj.hello();
  }
}
 
class BaseClassConstraintDemo {
  public static void Main() {
    A a = new A();
    B b = new B();
    C c = new C();
 
    // The following is valid because
    // A is the specified base class.
    Test<A> t1 = new Test<A>(a);
 
    t1.sayHello();
 
    // The following is valid because
    // B inherits A.
    Test<B> t2 = new Test<B>(b);
 
    t2.sayHello();
 
 
    // The following is invalid because
    // C does not inherit A.
//    Test<C> t3 = new Test<C>(c); // Error!
  }
}

listing 5
// A more practical demonstration of a base class constraint.
 
using System;
 
// A custom exception that is thrown if a name or number
// is not found.
class NotFoundException : ApplicationException {}
 
// A base class that stores a name and phone number.
class PhoneNumber {
  string name;
  string number;
 
  public PhoneNumber(string n, string num) {
    name = n;
    number = num;
  }
 
  public string Number {
    get { return number; }
    set { number = value; }
  }
 
  public string Name {
    get { return name; }
    set { name = value; }
  }
}
 
// A class of phone numbers for friends.
class Friend : PhoneNumber {
  bool isWorkNumber;
 
  public Friend(string n, string num, bool wk) :
    base(n, num)
  {
    isWorkNumber = wk;
  }
 
  public bool IsWorkNumber {
    get {
      return isWorkNumber;
    }
  }
 
  // ...
}
 
// A class of phone numbers for suppliers.
class Supplier : PhoneNumber {
  public Supplier(string n, string num) :
    base(n, num) { }
 
  // ...
}
 
// Notice that this class does not inherit PhoneNumber,
class EmailFriend {
 
  // ...
}
 
// PhoneList can manage any type of phone list
// as long as it is derived from PhoneNumber.
class PhoneList<T> where T : PhoneNumber {
  T[] phList;
  int end;
 
  public PhoneList() { 
    phList = new T[10];
    end = 0;
  }
 
  public bool add(T newEntry) {
    if(end == 10) return false;
 
    phList[end] = newEntry;
    end++;
 
    return true;
  }
 
  // Given a name, find and return the phone info.
  public T findByName(string name) {
 
    for(int i=0; i<end; i++) {
 
      // Name can be used because it is a member of
      // PhoneNumber, which is the base class constraint.
      if(phList[i].Name == name) 
        return phList[i];
 
    }
 
    // Name not in list.
    throw new NotFoundException();
  }
 
  // Given a number, find and return the phone info.
  public T findByNumber(string number) {
 
    for(int i=0; i<end; i++) {
 
      // Number can be used because it is also a member of
      // PhoneNumber which, is the base class constraint.
      if(phList[i].Number == number) 
        return phList[i];
    }
 
    // Number not in list.
    throw new NotFoundException();
  }
 
  // ...
}
 
// Demonstrate base clas constraints.
class UseBaseClassConstraint {
  public static void Main() {
 
    // The following code is OK because Friend
    // inherits PhoneNumber.
    PhoneList<Friend> plist = new PhoneList<Friend>();
    plist.add(new Friend("Tom", "555-1234", true));
    plist.add(new Friend("Gary", "555-6756", true));
    plist.add(new Friend("Matt", "555-9254", false));
 
    try {
      // Find the number of a friend given a name.
      Friend frnd = plist.findByName("Gary");
 
      Console.Write(frnd.Name + ": " + frnd.Number);
 
      if(frnd.IsWorkNumber)
        Console.WriteLine(" (work)");
      else
        Console.WriteLine();
    } catch(NotFoundException) {
      Console.WriteLine("Not Found");
    }
 
    Console.WriteLine();
 
    // The following code is also OK because Supplier
    // inherits PhoneNumber.
    PhoneList<Supplier> plist2 = new PhoneList<Supplier>();
    plist2.add(new Supplier("Global Hardware", "555-8834"));
    plist2.add(new Supplier("Computer Warehouse", "555-9256"));
    plist2.add(new Supplier("NetworkCity", "555-2564"));
 
    try {
      // Find the name of a supplier given a number
      Supplier sp = plist2.findByNumber("555-2564");
      Console.WriteLine(sp.Name + ": " + sp.Number);
    } catch(NotFoundException) {
        Console.WriteLine("Not Found");
    }
 
    // The following declaration is invalid
    // because EmailFriend does NOT inherit PhoneNumber.
//    PhoneList<EmailFriend> plist3 =
//        new PhoneList<EmailFriend>(); // Error!
 
  }
}


listing 6
// Use an interface constraint.
 
using System;
 
// A custom exception that is thrown if a name or number
// is not found.
class NotFoundException : ApplicationException { }
 
// An interface that supports a name and phone number.
public interface IPhoneNumber {
 
  string Number {
    get;
    set;
  }
 
  string Name {
    get;
    set;
  }
}
 
// A class of phone numbers for friends.
// It implements IPhoneNumber.
class Friend : IPhoneNumber {
  string name;
  string number;
 
  bool isWorkNumber;
 
  public Friend(string n, string num, bool wk) {
    name = n;
    number = num;
 
    isWorkNumber = wk;
  }
 
  public bool IsWorkNumber {
    get {
      return isWorkNumber;
    }
  }
 
  // Implement IPhoneNumber
  public string Number {
    get { return number; }
    set { number = value; }
  }
 
  public string Name {
    get { return name; }
    set { name = value; }
  }
 
  // ...
}
 
// A class of phone numbers for suppliers.
class Supplier : IPhoneNumber {
  string name;
  string number;
 
  public Supplier(string n, string num) {
    name = n;
    number = num;
  }
 
  // Implement IPhoneNumber
  public string Number {
    get { return number; }
    set { number = value; }
  }
 
  public string Name {
    get { return name; }
    set { name = value; }
  }
 
  // ...
}
 
// Notice that this class does not implement IPhoneNumber,
class EmailFriend {
 
  // ...
}
 
// PhoneList can manage any type of phone list
// as long as it is implements IPhoneNumber.
class PhoneList<T> where T : IPhoneNumber {
  T[] phList;
  int end;
 
  public PhoneList() { 
    phList = new T[10];
    end = 0;
  }
 
  public bool add(T newEntry) {
    if(end == 10) return false;
 
    phList[end] = newEntry;
    end++;
 
    return true;
  }
 
  // Given a name, find and return the phone info.
  public T findByName(string name) {
 
    for(int i=0; i<end; i++) {
 
      // Name can be used because it is a member of
      // IPhoneNumber, which is the interface constraint.
      if(phList[i].Name == name) 
        return phList[i];
 
    }
 
    // Name not in list.
    throw new NotFoundException();
  }
 
  // Given a number, find and return the phone info.
  public T findByNumber(string number) {
 
    for(int i=0; i<end; i++) {
 
      // Number can be used becasue it is also a member of
      // IPhoneNumber, which is the interface constraint.
      if(phList[i].Number == number) 
        return phList[i];
    }
 
    // Number not in list.
    throw new NotFoundException();
  }
 
  // ...
}
 
// Demonstrate interface constraints.
class UseInterfaceConstraint {
  public static void Main() {
 
    // The following code is OK because Friend
    // implements IPhoneNumber.
    PhoneList<Friend> plist = new PhoneList<Friend>();
    plist.add(new Friend("Tom", "555-1234", true));
    plist.add(new Friend("Gary", "555-6756", true));
    plist.add(new Friend("Matt", "555-9254", false));
 
    try {
      // Find the number of a friend given a name.
      Friend frnd = plist.findByName("Gary");
 
      Console.Write(frnd.Name + ": " + frnd.Number);
 
      if(frnd.IsWorkNumber)
        Console.WriteLine(" (work)");
      else
        Console.WriteLine();
    } catch(NotFoundException) {
      Console.WriteLine("Not Found");
    }
 
    Console.WriteLine();
 
    // The following code is also OK because Supplier
    // implements IPhoneNumber.
    PhoneList<Supplier> plist2 = new PhoneList<Supplier>();
    plist2.add(new Supplier("Global Hardware", "555-8834"));
    plist2.add(new Supplier("Computer Warehouse", "555-9256"));
    plist2.add(new Supplier("NetworkCity", "555-2564"));
 
    try {
      // Find the name of a supplier given a number
      Supplier sp = plist2.findByNumber("555-2564");
      Console.WriteLine(sp.Name + ": " + sp.Number);
    } catch(NotFoundException) {
        Console.WriteLine("Not Found");
    }
 
    // The following declaration is invalid
    // because EmailFriend does NOT implement IPhoneNumber.
//    PhoneList<EmailFriend> plist3 =
//        new PhoneList<EmailFriend>(); // Error!
  }
}

listing 7
// Demonstrate a new() constructor constraint.
 
using System;
 
class MyClass {
 
  public MyClass() {
    // ...
  }    
 
  //...
}
 
class Test<T> where T : new() {
  T obj;
 
  public Test() {
    // This works because of the new() constraint.
    obj = new T(); // create a T object
  }
 
  // ...
}
 
class ConsConstraintDemo {
  public static void Main() {
 
    Test<MyClass> x = new Test<MyClass>();
 
  }
}

listing 8
// Demonstrate a reference constriant.
 
using System;
 
class MyClass {
  //...
}
 
// Use a reference constraint.
class Test<T> where T : class {
  T obj;
 
  public Test() {
    // The following statement is legal only
    // because T is guaranteed to be a reference
    // type, which can be assigned the value null.
    obj = null;
  }
 
  // ...
}
 
class ClassConstraintDemo {
  public static void Main() {
 
    // The following is OK because MyClass is a class.
    Test<MyClass> x = new Test<MyClass>();
 
    // The next line is in error because int is 
    // a value type.
//    Test<int> y = new Test<int>();
  }
}

listing 9
// Demonstrate a value type constriant.
 
using System;
 
struct MyStruct {
  //...
}
 
class MyClass {
  // ...
}
 
class Test<T> where T : struct {
  T obj;
 
  public Test(T x) {
    obj = x;
  }
 
  // ...
}
 
class ValueConstraintDemo {
  public static void Main() {
 
    // Both of these declarations are legal.
 
    Test<MyStruct> x = new Test<MyStruct>(new MyStruct());
 
    Test<int> y = new Test<int>(10);
 
    // But, the following declaration is illegal!
//    Test<MyClass> z = new Test<MyClass>(new MyClass());
  }
}

listing 10
// Create relationship between two type parameters.
 
using System;
 
class A {
  //...
}
 
class B : A {
  // ...
}
 
// Here, V must inherit T.
class Gen<T, V> where V : T { 
  // ...
}
 
class NakedConstraintDemo {
  public static void Main() {
 
    // This declaration is OK because B inherits A.
    Gen<A, B> x = new Gen<A, B>();
 
    // This declaration is in error because
    // A does not inherit B.
//    Gen<B, A> y = new Gen<B, A>();
 
  }
}

listing 11
// Use multiple where clauses.
 
using System;
 
// Gen has two type arguments and both have
// a where clause.
class Gen<T, V> where T : class
                where V : struct { 
  T ob1; 
  V ob2; 
 
  public Gen(T t, V v) {
    ob1 = t;
    ob2 = v;
  }
}
 
class MultipleConstraintDemo {
  public static void Main() {
    // This is OK because string is a class and
    // int is a value type.
    Gen<string, int> obj = new Gen<string, int>("test", 11);
 
    // The next line is wrong because bool is not
    // a reference type.
//    Gen<bool, int> obj = new Gen<bool, int>(true, 11);
        
  }
}

listing 12
// Demonstrate the default keyword.
 
using System;
 
class MyClass {
  //...
}
 
// Construct a default object of T.
class Test<T> { 
  public T obj;
 
  public Test() {
    // The following statement would work
    // only for reference types.
//    obj = null;
 
    // This statement works for both 
    // reference and value types.
    obj = default(T);
  }
 
  // ...
}
 
class DefaultDemo {
  public static void Main() {
 
    // Construct Test using a reference type.
    Test<MyClass> x = new Test<MyClass>();
 
    if(x.obj == null)
      Console.WriteLine("x.obj is null.");
 
    // Construct Test using a value type.
    Test<int> y = new Test<int>();
 
    if(y.obj == 0)
      Console.WriteLine("y.obj is 0.");
  }
}

listing 13
// Demonstrate a generic struct.
using System;
 
// This structure is generic.
struct XY<T> {
  T x;
  T y;
 
  public XY(T a, T b) {
    x = a;
    y = b;
  }
 
  public T X {
    get { return x; }
    set { x = value; }
  }
 
  public T Y {
    get { return y; }
    set { y = value; }
  }
 
}
 
class StructTest {
  public static void Main() {
    XY<int> xy = new XY<int>(10, 20);
    XY<double> xy2 = new XY<double>(88.0, 99.0);
 
    Console.WriteLine(xy.X + ", " + xy.Y);
 
    Console.WriteLine(xy2.X + ", " + xy2.Y);
  }
}

listing 14
// Demonstrate a generic method.
 
using System;
 
// A class of array utilities.  Notice that this is not
// a generic class.
class ArrayUtils { 
 
  // Copy an array, inserting a new element
  // in the process.  This is a generic method.
  public static bool copyInsert<T>(T e, int idx,
                                   T[] src, T[] target) {
 
    // See if target array is big enough.
    if(target.Length < src.Length+1) 
      return false;
 
    // Copy src to target, inserting e at idx in the proecess.
    for(int i=0, j=0; i < src.Length; i++, j++) {
      if(i == idx) {
        target[j] = e;
        j++;
      }
      target[j] = src[i];
    }
    
    return true;
  }
}
 
class GenMethDemo {
  public static void Main() {
    int[] nums = { 1, 2, 3 };
    int[] nums2 = new int[4];
 
    // Display contents of nums.
    Console.Write("Contents of nums: ");
    foreach(int x in nums)
      Console.Write(x + " ");
 
    Console.WriteLine();
 
    // Operate on an int array.
    ArrayUtils.copyInsert(99, 2, nums, nums2);
 
    // Display contents of nums2.
    Console.Write("Contents of nums2: ");
    foreach(int x in nums2)
      Console.Write(x + " ");
 
    Console.WriteLine();
 
 
    // Now, use copyInsert on an array of strings.
    string[] strs = { "Generics", "are", "powerful."};
    string[] strs2 = new string[4];
 
    // Display contents of strs.
    Console.Write("Contents of strs: ");
    foreach(string s in strs)
      Console.Write(s + " ");
 
    Console.WriteLine();
 
    // Insert into a string array.
    ArrayUtils.copyInsert("in C#", 1, strs, strs2);
 
    // Display contents of strs2.
    Console.Write("Contents of strs2: ");
    foreach(string s in strs2)
      Console.Write(s + " ");
 
    Console.WriteLine();
 
    // This call is invalid because the first argument
    // if of type double, and the third and fourth arguments
    // have base types of int.
//    ArrayUtils.copyInsert(0.01, 2, nums, nums2);
 
  }
}

listing 15
// A simple generic delegate.
  
using System; 
 
// Declare a generic delegate.  
delegate T SomeOp<T>(T v); 
 
class GenDelegateDemo { 
  // Return the summation of the argument.
  static int sum(int v) {
    int result = 0;
    for(int i=v; i>0; i--)
      result += i;
 
    return result;
  }
 
  // Return a string containing the reverse of the argument.
  static string reflect(string str) {
    string result = "";
 
    foreach(char ch in str)
      result = ch + result;
 
    return result;
  }
     
  public static void Main() {  
    // Construct an int delegate. Notice use of method group
    // conversion on generic delegate.
    SomeOp<int> intDel = sum; 
    Console.WriteLine(intDel(3));
 
    // Construct a string delegate. Also use method group conversion.
    SomeOp<string> strDel = reflect; 
    Console.WriteLine(strDel("Hello"));
  } 
}

listing 16
// Convert event example from Chapter 15 to
// use generic delegate.
  
using System; 
 
// Derive a class from EventArgs. 
class MyEventArgs : EventArgs { 
  public int eventnum; 

 
// Declare a generic delegate for an event.  
delegate void MyEventHandler<T, V>(T source, V args);
 
// Declare an event class. 
class MyEvent { 
  static int count = 0; 
 
  public event MyEventHandler<MyEvent, MyEventArgs> SomeEvent; 
 
  // This fires SomeEvent. 
  public void OnSomeEvent() { 
    MyEventArgs arg = new MyEventArgs(); 
 
    if(SomeEvent != null) { 
      arg.eventnum = count++; 
      SomeEvent(this, arg); 
    } 
  } 

 
class X { 
  public void handler<T, V>(T source, V arg) where V : MyEventArgs { 
    Console.WriteLine("Event " + arg.eventnum + 
                      " received by an X object."); 
    Console.WriteLine("Source is " + source); 
    Console.WriteLine(); 
  } 

 
class Y {  
  public void handler<T,V>(T source, V arg) where V : MyEventArgs { 
    Console.WriteLine("Event " + arg.eventnum + 
                      " received by a Y object."); 
    Console.WriteLine("Source is " + source); 
    Console.WriteLine(); 
  } 

 
class UseGenericEventDelegate { 
  public static void Main() {  
    X ob1 = new X(); 
    Y ob2 = new Y(); 
    MyEvent evt = new MyEvent(); 
 
    // Add handler() to the event list. 
    evt.SomeEvent += ob1.handler; 
    evt.SomeEvent += ob2.handler; 
 
    // Fire the event. 
    evt.OnSomeEvent(); 
    evt.OnSomeEvent(); 
  } 
}

listing 17
// Demonstrate a generic interface.
 
using System;
 
public interface ISeries<T> {
  T getNext(); // return next element in series
  void reset(); // restart the series
  void setStart(T v); // set the starting element
}
 
// Implement ISeries.
class ByTwos<T> : ISeries<T> {
  T start;
  T val;
 
  // This delegate defines the form of a method
  // that will be called when the next element in
  // the series is needed.
  public delegate T IncByTwo(T v);
 
  // This delegate reference will be assigned the 
  // method passed to the ByTwos constructor.
  IncByTwo incr; 
 
  public ByTwos(IncByTwo incrMeth) {
    start = default(T);
    val = default(T);
    incr = incrMeth;
  }
 
  public T getNext() {
    val = incr(val);
    return val;
  }
 
  public void reset() {
    val = start;
  }
 
  public void setStart(T v) {
    start = v;
    val = start;
  }
}
 
class ThreeD {
  public int x, y, z;
 
  public ThreeD(int a, int b, int c) {
    x = a;
    y = b;
    z = c;
  }
}
  
 
class GenIntfDemo {
  // Define plus two for int.
  static int intPlusTwo(int v) {
    return v + 2;
  }
 
  // Define plus two for double.
  static double doublePlusTwo(double v) {
    return v + 2.0;
  }
 
  // Define plus two for ThreeD.
  static ThreeD ThreeDPlusTwo(ThreeD v) {
    if(v==null) return new ThreeD(0, 0, 0);
    else return new ThreeD(v.x + 2, v.y + 2, v.z + 2);
  }
 
  public static void Main() {
    // Demonstrate int series.
    ByTwos<int> intBT = new ByTwos<int>(intPlusTwo);
 
    for(int i=0; i < 5; i++)
      Console.Write(intBT.getNext() + "  ");
 
    Console.WriteLine();
 
 
    // Demonstrate double series.
    ByTwos<double> dblBT = new ByTwos<double>(doublePlusTwo);
 
    dblBT.setStart(11.4);
 
    for(int i=0; i < 5; i++)
      Console.Write(dblBT.getNext() + "  ");
 
    Console.WriteLine();
 
 
    // Demonstrate ThreeD series.
    ByTwos<ThreeD> ThrDBT = new ByTwos<ThreeD>(ThreeDPlusTwo);
 
    ThreeD coord;
    for(int i=0; i < 5; i++) {
      coord = ThrDBT.getNext();
      Console.Write(coord.x + "," +
                    coord.y + "," +
                    coord.z + "  ");
    }
 
    Console.WriteLine();
 
  }
}

listing 18
// This won't work!  
public static bool isIn<T>(T what, T[] obs) {
  foreach(T v in obs)
    if(v == what) // Error!
      return true;
 
  return false;
}

listing 19
// Demonstrate IComparable.
 
using System;
 
class MyClass : IComparable {
  public int val;
 
  public MyClass(int x) { val = x; }
 
  // Implement IComparable.
  public int CompareTo(object obj) {
    return val - ((MyClass) obj).val;
  }
}
 
class CompareDemo {
 
  // Require IComparable interface.
  public static bool isIn<T>(T what, T[] obs) where T : IComparable {
    foreach(T v in obs)
      if(v.CompareTo(what) == 0) // now OK, uses CompareTo()
        return true;
 
    return false;
  }
 
  // Demonstrate comparisons.
  public static void Main() {
    // Use isIn() with int.
    int[] nums = { 1, 2, 3, 4, 5 };
 
    if(isIn(2, nums))
      Console.WriteLine("2 is found.");
 
    if(isIn(99, nums))
      Console.WriteLine("This won't display.");
 
 
    // Use isIn() with string.
    string[] strs = { "one", "two", "Three"};
 
    if(isIn("two", strs))
      Console.WriteLine("two is found.");
 
    if(isIn("five", strs))
      Console.WriteLine("This won't display.");
 
 
    // Use isIn with MyClass.
    MyClass[] mcs = { new MyClass(1), new MyClass(2),
                      new MyClass(3), new MyClass(4) };
 
    if(isIn(new MyClass(3), mcs))
      Console.WriteLine("MyClass(3) is found.");
 
    if(isIn(new MyClass(99), mcs))
      Console.WriteLine("This won't display.");
  }
}

listing 20
// This version of MyClass implements IComparable<T>
class MyClass : IComparable<MyClass> {
  public int val;
 
  public MyClass(int x) { val = x; }
 
  public int CompareTo(MyClass obj) {
    return val - obj.val; // Now, no cast is needed.
  }
 
}

listing 21
// A simple generic class hierarchy.
using System;
 
// A generic base class.
class Gen<T> { 
  T ob;
   
  public Gen(T o) { 
    ob = o; 
  } 
 
  // Return ob. 
  public T getob() { 
    return ob; 
  } 

 
// A class derived from Gen.
class Gen2<T> : Gen<T> {
  public Gen2(T o) : base(o) {
    // ...
  }
}
 
class GenHierDemo {
  public static void Main() {
    Gen2<string> g2 = new Gen2<string>("Hello");
 
    Console.WriteLine(g2.getob());
  }
}

listing 22
// A derived class can add its own type parameters.
using System;
 
// A generic base class.
class Gen<T> { 
  T ob; // declare an object of type T 
   
  // Pass the constructor an object of
  // type T.
  public Gen(T o) { 
    ob = o; 
  } 
 
  // Return ob. 
  public T getob() { 
    return ob; 
  } 

 
// A derived class of Gen that defines a second
// type parameter, called V.
class Gen2<T, V> : Gen<T> {
  V ob2;
 
  public Gen2(T o, V o2) : base(o) {
    ob2 = o2;
  }
 
  public V getob2() {
    return ob2;
  }
}
 
// Create an object of type Gen2.
class GenHierDemo2 { 
  public static void Main() { 
   
    // Create a Gen2 object for string and int.
    Gen2<string, int> x =
      new Gen2<string, int>("Value is: ", 99); 
 
    Console.Write(x.getob());
    Console.WriteLine(x.getob2());
  } 
}

listing 23
// A nongeneric class can be the base class
// of a generic derived class.
using System;
 
// A nongeneric class.
class NonGen {
  int num;
 
  public NonGen(int i) {
    num = i;
  }
 
  public int getnum() {
    return num;
  }
}
 
// A generic derived class.
class Gen<T> : NonGen { 
  T ob;
   
  public Gen(T o, int i) : base (i) { 
    ob = o; 
  } 
 
  // Return ob. 
  public T getob() { 
    return ob; 
  } 

 
// Create a Gen object.
class HierDemo3 { 
  public static void Main() { 
   
    // Create a Gen object for string.
    Gen<String> w = new Gen<String>("Hello", 47);
   
    Console.Write(w.getob() + " ");
    Console.WriteLine(w.getnum());
  } 
}


listing 24
// Overriding a virtual method in a generic class. 
using System; 
 
// A generic base class. 
class Gen<T> {  
  protected T ob;  
    
  public Gen(T o) {  
    ob = o;  
  }  
  
  // Return ob. This method is virtual. 
  public virtual T getob() {  
    Console.Write("Gen's getob(): " ); 
    return ob;  
  }  
}  
 
// A derived class of Gen that overrides getob(). 
class Gen2<T> : Gen<T> { 
 
  public Gen2(T o) : base(o) {  } 
   
  // Override getob(). 
  public override T getob() {  
    Console.Write("Gen2's getob(): "); 
    return ob;  
  }  

  
// Demonstrate generic method override. 
class OverrideDemo {  
  public static void Main() {  
    
    // Create a Gen object for int. 
    Gen<int> iOb = new Gen<int>(88); 
 
    // This calls Gen's version of getob(). 
    Console.WriteLine(iOb.getob()); 
 
 
    // Now, create a Gen2 object and assign its 
    // reference to iOb (which is a Gen<int> variable).
    iOb = new Gen2<int>(99);  
 
    // This calls Gen2's verison of getob(). 
    Console.WriteLine(iOb.getob()); 
  }
}

listing 25
// Ambiguity can result when overloading
// methods that use type parameters.
//
// This program will not compile.
 
using System;
 
// A generic class that contains a potentially
// ambiguous overload of the set() method.
class Gen<T, V> { 
  T ob1; 
  V ob2; 
 
  // ...
 
  // In some cases, these two methods
  // will not differ in their parameter types.
  public void set(T o) {
    ob1 = o;
  }
 
  public void set(V o) {
    ob2 = o;
  }
}
 
class AmbiguityDemo {
  public static void Main() {
    Gen<int, double> ok = new Gen<int, double>();
 
    Gen<int, int> notOK = new Gen<int, int>();
 
    ok.set(10); // is valid, types differ
 
    notOK.set(10); // ambiguous, types are the same
    
  }
}


listing 1
// Demonstrate pointers and unsafe.
 
using System;
 
class UnsafeCode {
  // Mark Main as unsafe.
  unsafe public static void Main() {
    int count = 99;
    int* p; // create an int pointer
 
    p = &count; // put address of count into p
 
    Console.WriteLine("Initial value of count is " + *p);
 
    *p = 10; // assign 10 to count via p
    
    Console.WriteLine("New value of count is " + *p);
  }
}

listing 2
// Demonstrate fixed.
 
using System;
 
class Test {
  public int num;
  public Test(int i) { num = i; }
}
 
class FixedCode {
  // Mark Main as unsafe.
  unsafe public static void Main() {
    Test o = new Test(19);
 
    fixed (int* p = &o.num) { // use fixed to put address of o.num into p
 
      Console.WriteLine("Initial value of o.num is " + *p);
  
      *p = 10; // assign the to count via p
    
      Console.WriteLine("New value of o.num is " + *p);
    }
  }
}

listing 3
// Demonstrate the effects of pointer arithmethic.
 
using System;
 
class PtrArithDemo {
  unsafe public static void Main() {
    int x;
    int i; 
    double d;
 
    int* ip = &i;
    double* fp = &d;
 
    Console.WriteLine("int     double\n");
 
    for(x=0; x < 10; x++) {
       Console.WriteLine((uint) (ip) + " " +
                         (uint) (fp));
       ip++;
       fp++;
    }
  }
}

listing 4
// Demonstrate pointer comparison.
 
using System;
 
class PtrCompDemo {
  unsafe public static void Main() {
 
    int[] nums = new int[11];
    int x;
 
    // find the middle
    fixed (int* start = &nums[0]) { 
      fixed(int* end = &nums[nums.Length-1]) { 
        for(x=0; start+x <= end-x; x++) ;
      }
    }
    Console.WriteLine("Middle element is " + x);
  }
}

listing 5
/* An array name with an index yields a pointer to the
   start of the array. */
 
using System;
 
class PtrArray {
  unsafe public static void Main() {
    int[] nums = new int[10];
 
    fixed(int* p = &nums[0], p2 = nums) {
      if(p == p2)
        Console.WriteLine("p and p2 point to same address.");
    }
  }
}

listing 6
// Index a pointer as if it were an array.
 
using System;
 
class PtrIndexDemo {
  unsafe public static void Main() {
    int[] nums = new int[10];
 
    // index pointer
    Console.WriteLine("Index pointer like array.");
    fixed (int* p = nums) {
      for(int i=0; i < 10; i++) 
        p[i] = i; // index pointer like array
 
      for(int i=0; i < 10; i++) 
        Console.WriteLine("p[{0}]: {1} ", i, p[i]);
    }
 
    // use pointer arithmetic
    Console.WriteLine("\nUse pointer arithmetic.");
    fixed (int* p = nums) {
      for(int i=0; i < 10; i++) 
        *(p+i) = i; // use pointer arithmetic
 
      for(int i=0; i < 10; i++) 
        Console.WriteLine("*(p+{0}): {1} ", i, *(p+i));
    }
  }
}

listing 7
// Use fixed to get a pointer to the start of a string.
 
using System;
 
class FixedString {
  unsafe public static void Main() {
    string str = "this is a test";
 
    // Point p to start of str.
    fixed(char* p = str) {
 
      // Display the contents of str via p.
      for(int i=0; p[i] != 0; i++)
        Console.Write(p[i]);
    }
 
    Console.WriteLine();
    
  }
}

listing 8
using System;
 
class MultipleIndirect {
  unsafe public static void Main() {
    int x;    // holds an int value 
    int* p;  // holds an int pointer
    int** q; // holds an pointer to an int pointer
 
    x = 10;
    p = &x; // put address of x into p
    q = &p; // put address of p into q
 
    Console.WriteLine(**q); // display the value of x 
  }
}

listing 9
// Demonstrate stackalloc.
 
using System;
 
class UseStackAlloc {
  unsafe public static void Main() {
    int* ptrs = stackalloc int[3];
 
    ptrs[0] = 1;
    ptrs[1] = 2;
    ptrs[2] = 3;
 
    for(int i=0; i < 3; i++)
      Console.WriteLine(ptrs[i]);
  }
}

listing 10
// Demonstrate a fixed-size buffer.
 
using System; 
 
// Create a fixed size buffer.
unsafe struct FixedBankRecord {
  public fixed byte name[80]; // create a fixed-size buffer
  public double balance;
  public long ID;
}
 
class FixedSizeBuffer { 
  // mark Main as unsafe 
  unsafe public static void Main() { 
    Console.WriteLine("Size of FixedBankRecord is " + 
                       sizeof(FixedBankRecord));
  } 
}

listing 11
// Demonstrate a nullable type.
 
using System;
 
class NullableDemo {
  public static void Main() {
    int? count = null;
 
    if(count.HasValue)
      Console.WriteLine("count has this value: " + count.Value);
    else 
      Console.WriteLine("count has no value");
 
    count = 100;
 
    if(count.HasValue)
      Console.WriteLine("count has this value: " + count.Value);
    else 
      Console.WriteLine("count has no value");    
  }
}

listing 12
// Use nullable objects in expressions.
 
using System;
 
class NullableDemo {
  public static void Main() {
    int? count = null;
    int? result = null;
 
    int incr = 10; // notice that incr is a non-nullable type
 
    // result contains null, because count is null.
    result = count + incr;
 
    if(result.HasValue)
      Console.WriteLine("result has this value: " + result.Value);
    else 
      Console.WriteLine("result has no value");    
 
    // Now, count is given a value and result 
    // will contain a value.
    count = 100;
    result = count + incr;
 
    if(result.HasValue)
      Console.WriteLine("result has this value: " + result.Value);
    else 
      Console.WriteLine("result has no value");    
            
  }
}

listing 13
// Using ??
 
using System;
 
class NullableDemo2 {
  // Return a zero balance.
  static double getZeroBal() {
    Console.WriteLine("In getZeroBal().");
      return 0.0;
  }
 
  public static void Main() {
    double? balance = 123.75;
    double currentBalance;
 
    // Here, getZeroBal( ) is not called because balance
    // contains a value.
    currentBalance = balance ?? getZeroBal();
 
    Console.WriteLine(currentBalance);
  }
}

listing 14
partial class XY {
  public XY(int a, int b) {
    x = a;
    y = b;
  }
}

listing 15
partial class XY {
  int x;
 
  public int X {
    get { return x; }
    set { x = value; }
  }
}

listing 16
partial class XY {
  int y;
 
  public int Y {
    get { return y; }
    set { y = value; }
  }
}

listing 17
// Demonstrate partial class definitions.
using System;
 
class Test {
  public static void Main() {
    XY xy = new XY(1, 2);
 
 
    Console.WriteLine(xy.X + "," + xy.Y);
  }
}

listing 18
// Demonstrate readonly.
 
using System;
 
class MyClass {
  public static readonly int SIZE = 10;
}
 
class DemoReadOnly {
  public static void Main() {
    int[] nums = new int[MyClass.SIZE];
 
    for(int i=0; i<MyClass.SIZE; i++)
      nums[i] = i;
 
    foreach(int i in nums)
      Console.Write(i + " ");
 
    // MyClass.SIZE = 100; // Error!!! can't change
  }
}

listing 19
// Demonstrate using statement.
 
using System;
using System.IO;
 
class UsingDemo {
  public static void Main() {
    StreamReader sr = new StreamReader("test.txt");
 
    // Use object inside using statement.
    using(sr) {
      Console.WriteLine(sr.ReadLine());
      sr.Close();
    }
 
    // Create StreamReader inside the using statement.
    using(StreamReader sr2 = new StreamReader("test.txt")) {
      Console.WriteLine(sr2.ReadLine());
      sr2.Close();
    }
  }
}

listing 20
#include <stdlib.h>
 
int __declspec(dllexport) absMax(int a, int b) {
  return abs(a) < abs(b) ? abs(b) : abs(a);
}

listing 21
using System;
using System.Runtime.InteropServices;
 
class ExternMeth {
 
  // Here an extern method is declared.
  [DllImport("ExtMeth.dll")]
  public extern static int absMax(int a, int b);
 
  public static void Main() {
 
    // Use the extern method.
    int max = absMax(-10, -20);
    Console.WriteLine(max);
 
  }
}

listing 22
using System;
 
namespace MyNS {
 
  public class MyClass {
    public MyClass() {
      Console.WriteLine("Constructing from MyClass1.dll.");
    }
  }
}

listing 23
using System;
 
namespace MyNS {
  public class MyClass {
    public MyClass() {
      Console.WriteLine("Constructing from MyClass2.dll.");
    }
  }
}

listing 24
// extern alias statements must be at the top of the file.
extern alias Asm1;
extern alias Asm2;
 
using System;
 
class Demo {
  public static void Main() {
    Asm1::MyNS.MyClass t = new Asm1::MyNS.MyClass();
    Asm2::MyNS.MyClass t2 = new Asm2::MyNS.MyClass();
  }
}

listing 1
// Implement the Pythagorean Theorem.
 
using System; 
 
class Pythagorean {    
  public static void Main() {    
    double s1;
    double s2;
    double hypot;
    string str;
 
    Console.WriteLine("Enter length of first side: ");
    str = Console.ReadLine();
    s1 = Double.Parse(str);
 
    Console.WriteLine("Enter length of second side: ");
    str = Console.ReadLine();
    s2 = Double.Parse(str);
 
    hypot = Math.Sqrt(s1*s1 + s2*s2);
 
    Console.WriteLine("Hypotenuse is " + hypot);
  }    
}

listing 2
/* Compute the initial investment needed to attain
   a known future value given annual rate of return
   and the time period in years. */
 
using System; 
 
class InitialInvestment {    
  public static void Main() {    
    decimal InitInvest; // initial investment
    decimal FutVal;     // future value
 
    double NumYears;    // number of years 
    double IntRate;     // annual rate of return as a decimal
 
    string str; 
 
    Console.Write("Enter future value: ");
    str = Console.ReadLine();
    try { 
      FutVal = Decimal.Parse(str); 
    } catch(FormatException exc) { 
      Console.WriteLine(exc.Message); 
      return; 
    } 
 
    Console.Write("Enter interest rate (such as 0.085): ");
    str = Console.ReadLine();
    try { 
      IntRate = Double.Parse(str); 
    } catch(FormatException exc) { 
      Console.WriteLine(exc.Message); 
      return; 
    } 
 
    Console.Write("Enter number of years: ");
    str = Console.ReadLine();
    try { 
      NumYears = Double.Parse(str); 
    } catch(FormatException exc) { 
      Console.WriteLine(exc.Message); 
      return; 
    } 
 
    InitInvest = FutVal / (decimal) Math.Pow(IntRate+1.0, NumYears); 
 
    Console.WriteLine("Initial investment required: {0:C}",
                      InitInvest); 
  }    
}

listing 3
// Manually create a decimal number.
 
using System; 
 
class CreateDec {    
  public static void Main() {    
    decimal d = new decimal(12345, 0, 0, false, 2);
 
    Console.WriteLine(d);
  }    
}

listing 4
// Demonstrate several Char methods.
 
using System; 
 
class CharDemo {    
  public static void Main() {    
    string str = "This is a test. $23";
    int i;
 
    for(i=0; i < str.Length; i++) {
      Console.Write(str[i] + " is");
      if(Char.IsDigit(str[i]))
        Console.Write(" digit");
      if(Char.IsLetter(str[i]))
        Console.Write(" letter");
      if(Char.IsLower(str[i]))
        Console.Write(" lowercase");
      if(Char.IsUpper(str[i]))
        Console.Write(" uppercase");
      if(Char.IsSymbol(str[i]))
        Console.Write(" symbol");
      if(Char.IsSeparator(str[i]))
        Console.Write(" separator");
      if(Char.IsWhiteSpace(str[i]))
        Console.Write(" whitespace");
      if(Char.IsPunctuation(str[i]))
        Console.Write(" punctuation");
 
      Console.WriteLine();
    }
 
    Console.WriteLine("Original: " + str);
 
    // Convert to upper case.   
    string newstr = "";
    for(i=0; i < str.Length; i++)
      newstr += Char.ToUpper(str[i]);
 
    Console.WriteLine("Uppercased: " + newstr);
 
  }    
}

listing 5
// Sort an array and search for a value.
 
using System; 
 
class SortDemo {    
  public static void Main() {    
    int[] nums = { 5, 4, 6, 3, 14, 9, 8, 17, 1, 24, -1, 0 };
  
    // Display original order.
    Console.Write("Original order: ");
    foreach(int i in nums) 
      Console.Write(i + " ");
    Console.WriteLine();
 
    // Sort the array.
    Array.Sort(nums);
 
    // Display sorted order.
    Console.Write("Sorted order:   ");
    foreach(int i in nums) 
      Console.Write(i + " ");
    Console.WriteLine();
 
 
    // Search for 14.
    int idx = Array.BinarySearch(nums, 14);
 
    Console.WriteLine("Index of 14 is " + idx);
  }    
}

listing 6
// Sort and search an array of objects.
 
using System; 
 
class MyClass : IComparable<MyClass> {
  public int i;
 
  public MyClass(int x) { i = x; }
 
  // Implement IComparable<MyClass>.
  public int CompareTo(MyClass v) {
    return i - v.i;
  }
 
}
 
class SortDemo {    
  public static void Main() {    
    MyClass[] nums = new MyClass[5];
 
    nums[0] = new MyClass(5);
    nums[1] = new MyClass(2);
    nums[2] = new MyClass(3);
    nums[3] = new MyClass(4);
    nums[4] = new MyClass(1);
  
    // Display original order.
    Console.Write("Original order: ");
    foreach(MyClass o in nums) 
      Console.Write(o.i + " ");
    Console.WriteLine();
 
    // Sort the array.
    Array.Sort(nums);
 
    // Display sorted order.
    Console.Write("Sorted order:   ");
    foreach(MyClass o in nums) 
      Console.Write(o.i + " ");
    Console.WriteLine();
 
    // Search for MyClass(2).
    MyClass x = new MyClass(2);
    int idx = Array.BinarySearch(nums, x);
 
    Console.WriteLine("Index of MyClass(2) is " + idx);
  }    
}

listing 7
// Reverse an array.
 
using System; 
 
class ReverseDemo {    
  public static void Main() {    
    int[] nums = { 1, 2, 3, 4, 5 };
  
    // Display original order.
    Console.Write("Original order: ");
    foreach(int i in nums) 
      Console.Write(i + " ");
    Console.WriteLine();
 
    // Reverse the entire array.
    Array.Reverse(nums);
 
    // Display reversed order.
    Console.Write("Reversed order: ");
    foreach(int i in nums) 
      Console.Write(i + " ");
    Console.WriteLine();
 
    // Reverse a range.
    Array.Reverse(nums, 1, 3);
 
    // Display reversed order.
    Console.Write("Range reversed: ");
    foreach(int i in nums) 
      Console.Write(i + " ");
    Console.WriteLine();
  }
}

listing 8
// Copy an array.
 
using System; 
 
class CopyDemo {    
  public static void Main() {    
    int[] source = { 1, 2, 3, 4, 5 };
    int[] target = { 11, 12, 13, 14, 15 };
    int[] source2 = { -1, -2, -3, -4, -5 };
 
    // Display source.
    Console.Write("source: ");
    foreach(int i in source) 
      Console.Write(i + " ");
    Console.WriteLine();
 
    // Display original target.
    Console.Write("Original contents of target: ");
    foreach(int i in target) 
      Console.Write(i + " ");
    Console.WriteLine();
 
    // Copy the entire array.
    Array.Copy(source, target, source.Length);
 
    // Display copy.
    Console.Write("target after copy:  ");
    foreach(int i in target) 
      Console.Write(i + " ");
    Console.WriteLine();
 
    // Copy into middle of target.
    Array.Copy(source2, 2, target, 3, 2);
 
    // Display copy.
    Console.Write("target after copy:  ");
    foreach(int i in target) 
      Console.Write(i + " ");
    Console.WriteLine();
  }
}

listing 9
// Demonstrate Predicate delegate.
 
using System;  
 
class PredDemo {     
 
  // A predicate method. 
  // Returns true if v is negative.
  static bool isNeg(int v) {
    if(v < 0) return true;
    return false;
  }
 
  public static void Main() {     
    int[] nums = { 1, 4, -1, 5, -9 };
   
    Console.Write("Contents of nums: "); 
    foreach(int i in nums)  
      Console.Write(i + " "); 
    Console.WriteLine(); 
 
    // First see if nums contains a negative value.
    if(Array.Exists(nums, PredDemo.isNeg)) {
      Console.WriteLine("nums contains a negative value.");
 
      // Now, find first negative value.
      int x = Array.Find(nums, PredDemo.isNeg);
      Console.WriteLine("First negative value is : " + x);
    }
    else 
      Console.WriteLine("nums contains no negative values.");
  }     
}

listing 10
// Demonstrate an Action
  
using System;   
  
class MyClass {
  public int i; 
  
  public MyClass(int x) { i = x; } 

 
class ActionDemo {      
 
  // An Action method.
  // Displays the value it is passed.
  static void show(MyClass o) {
    Console.Write(o.i + " ");
  }
 
  // Another Action method.
  // Negates the value it is passed.
  static void neg(MyClass o) { 
    o.i = -o.i;
  } 
 
  public static void Main() {      
    MyClass[] nums = new MyClass[5]; 
 
    nums[0] = new MyClass(5); 
    nums[1] = new MyClass(2); 
    nums[2] = new MyClass(3); 
    nums[3] = new MyClass(4); 
    nums[4] = new MyClass(1); 
    
    Console.Write("Contents of nums: ");  
 
    // Use action to show the values.
    Array.ForEach(nums, ActionDemo.show);
 
    Console.WriteLine();  
 
    // Use action to negate the values.
    Array.ForEach(nums, ActionDemo.neg);
  
    Console.Write("Contents of nums negated: ");  
 
    // Use action to negate the values again.
    Array.ForEach(nums, ActionDemo.show);
 
    Console.WriteLine();  
  }      
}

listing 11
// An automated pair of dice.
 
using System; 
 
class RandDice {    
  public static void Main() {    
    Random ran = new Random();
 
    Console.Write(ran.Next(1, 7) + " "); 
    Console.WriteLine(ran.Next(1, 7)); 
  }    
}

listing 12
// Demonstrate ICloneable.
 
using System; 
 
class X {
  public int a;
 
  public X(int x) { a = x; }
}
 
class Test : ICloneable {
  public X o;
  public int b;
 
  public Test(int x, int y) {
    o = new X(x);
    b = y;
  }
 
  public void show(string name) {
    Console.Write(name + " values are ");
    Console.WriteLine("o.a: {0}, b: {1}", o.a, b);
  }
 
  // Make a deep copy of the invoking object.
  public object Clone() {
    Test temp = new Test(o.a, b);
    return temp;
  }
    
}
 
class CloneDemo {    
  public static void Main() {    
    Test ob1 = new Test(10, 20);
 
    ob1.show("ob1");
 
    Console.WriteLine("Make ob2 a clone of ob1.");
    Test ob2 = (Test) ob1.Clone();
 
    ob2.show("ob2");
 
    Console.WriteLine("Changing ob1.o.a to 99 and ob1.b to 88.");
    ob1.o.a = 99;
    ob1.b = 88;
 
    ob1.show("ob1");
    ob2.show("ob2");
  }
}

listing 1
// Compare strings.
 
using System;
 
class CompareDemo {
  public static void Main() {
    string str1 = "one";
    string str2 = "one";
    string str3 = "ONE";
    string str4 = "two";
    string str5 = "one, too";
 
 
    if(String.Compare(str1, str2) == 0)
      Console.WriteLine(str1 + " and " + str2 +
                        " are equal.");
    else
      Console.WriteLine(str1 + " and " + str2 +
                        " are not equal.");
 
 
    if(String.Compare(str1, str3) == 0)
      Console.WriteLine(str1 + " and " + str3 +
                        " are equal.");
    else
      Console.WriteLine(str1 + " and " + str3 +
                        " are not equal.");
 
    if(String.Compare(str1, str3, true) == 0)
      Console.WriteLine(str1 + " and " + str3 +
                        " are equal ignoring case.");
    else
      Console.WriteLine(str1 + " and " + str3 +
                        " are not equal ignoring case.");
 
     if(String.Compare(str1, str5) == 0)
      Console.WriteLine(str1 + " and " + str5 +
                        " are equal.");
    else
      Console.WriteLine(str1 + " and " + str5 +
                        " are not equal.");
 
    if(String.Compare(str1, 0, str5, 0, 3) == 0)
      Console.WriteLine("First part of " + str1 + " and " +
                        str5 + " are equal.");
    else
      Console.WriteLine("First part of " + str1 + " and " +
                        str5 + " are not equal.");
 
    int result = String.Compare(str1, str4);
    if(result < 0)
      Console.WriteLine(str1 + " is less than " + str4);
    else if(result > 0)
      Console.WriteLine(str1 + " is greater than " + str4);
    else
      Console.WriteLine(str1 + " equals " + str4);
  }
}

listing 2
// Compare strings using StringComparison enumeration. 
 
using System; 
 
class StrCompDemo { 
  public static void Main() { 
    string pswd = "we~23&blx$"; 
 
    string str;
 
    Console.WriteLine("Enter password: ");
    str = Console.ReadLine();
 
    // Compare using invariant culture.
    if(String.Compare(pswd, str,
                      StringComparison.InvariantCulture) == 0)
      Console.WriteLine("Password accepted.");
    else 
      Console.WriteLine("Password invalid.");
  }
}

listing 3
// Demonstrate Concat().
 
using System;
 
class ConcatDemo {
  public static void Main() {
 
    string result = String.Concat("This ", "is ", "a ",
                                  "test ", "of ", "the ",
                                  "String ", "class.");
 
    Console.WriteLine("result: " + result);
 
  }
}

listing 4
// Demonstrate the object form of Concat(). 
 
using System; 
 
class MyClass {
  public static int count = 0;
 
  public MyClass() { count++; }
}
 
class ConcatDemo { 
  public static void Main() { 
 
    string result = String.Concat("The value is " + 19);
    Console.WriteLine("result: " + result); 
 
    result = String.Concat("hello ", 88, " ", 20.0, " ",
                           false, " ",  23.45M); 
    Console.WriteLine("result: " + result); 
 
    MyClass mc = new MyClass();
 
    result = String.Concat(mc, " current count is ",
                           MyClass.count);
    Console.WriteLine("result: " + result); 
  } 
}

listing 5
// Search strings.
 
using System;
 
class StringSearchDemo {
  public static void Main() {
    string str = "C# has powerful string handling.";
    int idx;
 
    Console.WriteLine("str: " + str);
 
    idx = str.IndexOf('h');
    Console.WriteLine("Index of first 'h': " + idx);
 
    idx = str.LastIndexOf('h');
    Console.WriteLine("Index of last 'h': " + idx);
 
    idx = str.IndexOf("ing");
    Console.WriteLine("Index of first \"ing\": " + idx);
 
    idx = str.LastIndexOf("ing");
    Console.WriteLine("Index of last \"ing\": " + idx);
 
    char[] chrs = { 'a', 'b', 'c' };
    idx = str.IndexOfAny(chrs);
    Console.WriteLine("Index of first 'a', 'b', or 'c': " + idx);
 
    if(str.StartsWith("C# has"))
      Console.WriteLine("str begins with \"C# has\"");
 
    if(str.EndsWith("ling."))
      Console.WriteLine("str ends with \"ling.\"");
  }
}

listing 6
// Demonstrate Contains().
 
using System; 
 
class ContainsDemo { 
  public static void Main() { 
    string str = "C# combines power with performance.";
 
    if(str.Contains("power")) 
      Console.WriteLine("The sequence power was found.");
 
    if(str.Contains("pow"))
      Console.WriteLine("The sequence pow was found.");
 
    if(!str.Contains("powerful"))
      Console.WriteLine("The sequence powerful was not found.");
  } 
}

listing 7
// Split and join strings.
 
using System;
 
class SplitAndJoinDemo {
  public static void Main() {
    string str = "One if by land, two if by sea.";
    char[] seps = {' ', '.', ',' };
 
    // Split the string into parts.
    string[] parts = str.Split(seps);
    Console.WriteLine("Pieces from split: ");
    for(int i=0; i < parts.Length; i++)
      Console.WriteLine(parts[i]);
   
    // Now, join the parts.
    string whole = String.Join(" | ", parts);
    Console.WriteLine("Result of join: ");
    Console.WriteLine(whole);
  }
}

listing 8
// Tokenize strings.
 
using System;
 
class TokenizeDemo {
  public static void Main() {
    string[] input = {
                      "100 + 19",
                      "100 / 3.3",
                      "-3 * 9",
                      "100 - 87"
                     };
    char[] seps = {' '};
 
    for(int i=0; i < input.Length; i++) {
      // split string into parts
      string[] parts = input[i].Split(seps);
      Console.Write("Command: ");
      for(int j=0; j < parts.Length; j++)
        Console.Write(parts[j] + " ");
   
      Console.Write(", Result: ");
      double n = Double.Parse(parts[0]);
      double n2 = Double.Parse(parts[2]);
 
      switch(parts[1]) {
        case "+":
          Console.WriteLine(n + n2);
          break;
        case "-":
          Console.WriteLine(n - n2);
          break;
        case "*":
          Console.WriteLine(n * n2);
          break;
        case "/":
          Console.WriteLine(n / n2);
          break;
      }
    }
  }
}

listing 9
// Trimming and padding.
 
using System; 
 
class TrimPadDemo { 
  public static void Main() { 
    string str = "test";
 
    Console.WriteLine("Original string: " + str);
    
    // Pad on left with spaces.
    str = str.PadLeft(10);
    Console.WriteLine("|" + str + "|");
 
    // Pad on right with spaces.
    str = str.PadRight(20);
    Console.WriteLine("|" + str + "|");
 
    // Trim spaces.
    str = str.Trim();
    Console.WriteLine("|" + str + "|");
 
    // Pad on left with #s.
    str = str.PadLeft(10, '#');
    Console.WriteLine("|" + str + "|");
 
    // Pad on right with #s.
    str = str.PadRight(20, '#');
    Console.WriteLine("|" + str + "|");
 
    // Trim #s.
    str = str.Trim('#');
    Console.WriteLine("|" + str + "|");
  }
}

listing 10
// Inserting, replacing, and removing.
 
using System; 
 
class InsRepRevDemo { 
  public static void Main() { 
    string str = "This test";
 
    Console.WriteLine("Original string: " + str);
    
    // Insert
    str = str.Insert(5, "is a ");
    Console.WriteLine(str);
 
    // Replace string
    str = str.Replace("is", "was");
    Console.WriteLine(str);
 
    // Replace characters
    str = str.Replace('a', 'X');
    Console.WriteLine(str);
 
    // Remove
    str = str.Remove(4, 5);
    Console.WriteLine(str);
  }
}

listing 11
// Use Substring().
 
using System; 
 
class SubstringDemo { 
  public static void Main() { 
    string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
    Console.WriteLine("str: " + str);
    
    Console.Write("str.Substring(15): ");
    string substr = str.Substring(15);
    Console.WriteLine(substr);
 
    Console.Write("str.Substring(0, 15): ");
    substr = str.Substring(0, 15);
    Console.WriteLine(substr);
  }
}

listing 12
// Demonstrate various format specifiers.
 
using System; 
 
class FormatDemo { 
  public static void Main() { 
    double v = 17688.65849; 
    double v2 = 0.15; 
    int x = 21; 
  
    Console.WriteLine("{0:F2}", v); 
 
    Console.WriteLine("{0:N5}", v); 
 
    Console.WriteLine("{0:e}", v); 
 
    Console.WriteLine("{0:r}", v); 
 
    Console.WriteLine("{0:p}", v2); 
 
    Console.WriteLine("{0:X}", x); 
 
    Console.WriteLine("{0:D12}", x); 
 
    Console.WriteLine("{0:C}", 189.99); 
  } 
}

listing 13
using System;  
  
class FormatDemo2 {  
  public static void Main() {  
 
    // Format the same argument three different ways:   
    Console.WriteLine("{0:F2}  {0:F3}  {0:e}", 10.12345);  
  
    // Display arguments in non-sequential order.
    Console.WriteLine("{2:d} {0:d} {1:d}", 1, 2, 3);  
  }  
}

listing 14
// Use String.Format() to format a value. 
 
using System; 
 
class FormatDemo { 
  public static void Main() { 
    double v = 17688.65849; 
    double v2 = 0.15; 
    int x = 21; 
  
    string str = String.Format("{0:F2}", v); 
    Console.WriteLine(str); 
 
    str = String.Format("{0:N5}", v); 
    Console.WriteLine(str); 
 
    str = String.Format("{0:e}", v); 
    Console.WriteLine(str); 
 
    str = String.Format("{0:r}", v); 
    Console.WriteLine(str); 
 
    str = String.Format("{0:p}", v2); 
    Console.WriteLine(str); 
 
    str = String.Format("{0:X}", x); 
    Console.WriteLine(str); 
 
    str = String.Format("{0:D12}", x); 
    Console.WriteLine(str); 
 
    str = String.Format("{0:C}", 189.99);
    Console.WriteLine(str);
  } 
}

listing 15
// A closer look at Format().
 
using System; 
 
class FormatDemo2 { 
  public static void Main() { 
    int i;
    int sum = 0;
    int prod = 1;
    string str;
 
    /* Display the running sum and product
       for the numbers 1 through 10. */
    for(i=1; i <= 10; i++) {
      sum += i;
      prod *= i;
      str = String.Format("Sum:{0,3:D}  Product:{1,8:D}",
                          sum, prod);
      Console.WriteLine(str);
    }
  }
}

listing 16
// Use ToString() to format values.
 
using System;
 
class ToStringDemo {
  public static void Main() {
    double v = 17688.65849;
    double v2 = 0.15;
    int x = 21;
 
    string str = v.ToString("F2");
    Console.WriteLine(str);
 
    str = v.ToString("N5");
    Console.WriteLine(str);
 
    str = v.ToString("e");
    Console.WriteLine(str);
 
    str = v.ToString("r");
    Console.WriteLine(str);
 
    str = v2.ToString("p");
    Console.WriteLine(str);
 
    str = x.ToString("X");
    Console.WriteLine(str);
 
    str = x.ToString("D12");
    Console.WriteLine(str);
 
    str = 189.99.ToString("C");
    Console.WriteLine(str);
  }
}

listing 17
// Using custom formats.
 
using System; 
 
class PictureFormatDemo { 
  public static void Main() { 
    double num = 64354.2345;
 
    Console.WriteLine("Default format: " + num);
 
    // Display with 2 decimal places.
    Console.WriteLine("Value with two decimal places: " +
                      "{0:#.##}", num);
 
    // Display with commas and 2 decimal places.
    Console.WriteLine("Add commas: {0:#,###.##}", num);
 
    // Display using scientific notation.
    Console.WriteLine("Use scientific notation: " +
                      "{0:#.###e+00}", num);
 
    // Scale the value by 1000.
    Console.WriteLine("Value in 1,000s: " +
                      "{0:#0,}", num);
 
    /* Display positive, negative, and zero
       values differently. */
    Console.WriteLine("Display positive, negative, " +
                      "and zero values differently.");
    Console.WriteLine("{0:#.#;(#.##);0.00}", num);
    num = -num;
    Console.WriteLine("{0:#.##;(#.##);0.00}", num);
    num = 0.0;
    Console.WriteLine("{0:#.##;(#.##);0.00}", num);
 
    // Display a percentage.
    num = 0.17;    
    Console.WriteLine("Display a percentage: {0:#%}", num);
  }
}

listing 18
// Format time and date information.
 
using System; 
 
class TimeAndDateFormatDemo { 
  public static void Main() { 
    DateTime dt = DateTime.Now; // obtain current time
 
    Console.WriteLine("d format: {0:d}", dt);
    Console.WriteLine("D format: {0:D}", dt);
 
    Console.WriteLine("t format: {0:t}", dt);
    Console.WriteLine("T format: {0:T}", dt);
 
    Console.WriteLine("f format: {0:f}", dt);
    Console.WriteLine("F format: {0:F}", dt);
 
    Console.WriteLine("g format: {0:g}", dt);
    Console.WriteLine("G format: {0:G}", dt);
 
    Console.WriteLine("m format: {0:m}", dt);
    Console.WriteLine("M format: {0:M}", dt);
 
    Console.WriteLine("r format: {0:r}", dt);
    Console.WriteLine("R format: {0:R}", dt);
 
    Console.WriteLine("s format: {0:s}", dt);
 
    Console.WriteLine("u format: {0:u}", dt);
    Console.WriteLine("U format: {0:U}", dt);
 
    Console.WriteLine("y format: {0:y}", dt);
    Console.WriteLine("Y format: {0:Y}", dt);
  }
}

listing 19
// A simple clock.
 
using System; 
 
class SimpleClock { 
  public static void Main() { 
    string t;
    int seconds;
 
    DateTime dt = DateTime.Now;
    seconds = dt.Second;
 
    for(;;) {
      dt = DateTime.Now;
 
      // update time if seconds change
      if(seconds != dt.Second) {
        seconds = dt.Second;
 
        t = dt.ToString("T");
 
        if(dt.Minute==0 && dt.Second==0) 
          t = t + "\a"; // ring bell at top of hour
 
        Console.WriteLine(t);
      }
    }
  }
}

listing 20
// Format time and date information.
 
using System; 
 
class CustomTimeAndDateFormatsDemo { 
  public static void Main() { 
    DateTime dt = DateTime.Now;
 
    Console.WriteLine("Time is {0:hh:mm tt}", dt);
    Console.WriteLine("24 hour time is {0:HH:mm}", dt);
    Console.WriteLine("Date is {0:ddd MMM dd, yyyy}", dt);
 
    Console.WriteLine("Era: {0:gg}", dt);
 
    Console.WriteLine("Time with seconds: " +
                      "{0:HH:mm:ss tt}", dt);
 
    Console.WriteLine("Use m for day of month: {0:m}", dt);
    Console.WriteLine("use m for minutes: {0:%m}", dt);
  }
}

listing 21
// Format an enumeration.
 
using System;
 
class EnumFmtDemo {
  enum Direction { North, South, East, West }
  [Flags] enum Status { Ready=0x1, OffLine=0x2, 
                        Waiting=0x4, TransmitOK=0x8,
                        RecieveOK=0x10, OnLine=0x20 }
 
  public static void Main() {
    Direction d = Direction.West;
 
    Console.WriteLine("{0:G}", d);
    Console.WriteLine("{0:F}", d);
    Console.WriteLine("{0:D}", d);
    Console.WriteLine("{0:X}", d);
    
    Status s = Status.Ready | Status.TransmitOK;
 
    Console.WriteLine("{0:G}", s);
    Console.WriteLine("{0:F}", s);
    Console.WriteLine("{0:D}", s);
    Console.WriteLine("{0:X}", s);
  }
}

listing 1
// Create a thread of execution.
 
using System;
using System.Threading;
 
class MyThread {
  public int count;
  string thrdName;
 
  public MyThread(string name) {
    count = 0;
    thrdName = name;
  }
 
  // Entry point of thread.
  public void run() {
    Console.WriteLine(thrdName + " starting.");
 
    do {
      Thread.Sleep(500);
      Console.WriteLine("In " + thrdName +
                        ", count is " + count);
      count++;
    } while(count < 10);
 
    Console.WriteLine(thrdName + " terminating.");
  }
}
 
class MultiThread {
  public static void Main() {
    Console.WriteLine("Main thread starting.");
 
    // First, construct a MyThread object.
    MyThread mt = new MyThread("Child #1");
 
    // Next, construct a thread from that object.
    Thread newThrd = new Thread(new ThreadStart(mt.run));
 
    // Finally, start execution of the thread.
    newThrd.Start();
 
    do {
      Console.Write(".");
      Thread.Sleep(100);
    } while (mt.count != 10);
 
    Console.WriteLine("Main thread ending.");
  }
}

listing 2
// An alternate way to start a thread.
 
using System;
using System.Threading;
 
class MyThread {
  public int count;
  public Thread thrd;
 
  public MyThread(string name) {
    count = 0;
    thrd = new Thread(this.run); // use method group conversion
    thrd.Name = name; // set the name of the thread
    thrd.Start(); // start the thread
  }
 
  // Entry point of thread.
  void run() {
    Console.WriteLine(thrd.Name + " starting.");
 
    do {
      Thread.Sleep(500);
      Console.WriteLine("In " + thrd.Name +
                        ", count is " + count);
      count++;
    } while(count < 10);
 
    Console.WriteLine(thrd.Name + " terminating.");
  }
}
 
class MultiThreadImproved {
  public static void Main() {
    Console.WriteLine("Main thread starting.");
 
    // First, construct a MyThread object.
    MyThread mt = new MyThread("Child #1");
 
    do {
      Console.Write(".");
      Thread.Sleep(100);
    } while (mt.count != 10);
 
    Console.WriteLine("Main thread ending.");
  }
}

listing 3
// Create multiple threads of execution.
 
using System;
using System.Threading;
 
class MyThread {
  public int count;
  public Thread thrd;
 
  public MyThread(string name) {
    count = 0;
    thrd = new Thread(this.run);
    thrd.Name = name;
    thrd.Start();
  }
 
  // Entry point of thread.
  void run() {
    Console.WriteLine(thrd.Name + " starting.");
 
    do {
      Thread.Sleep(500);
      Console.WriteLine("In " + thrd.Name +
                        ", count is " + count);
      count++;
    } while(count < 10);
 
    Console.WriteLine(thrd.Name + " terminating.");
  }
}
 
class MoreThreads {
  public static void Main() {
    Console.WriteLine("Main thread starting.");
 
    // Construct three threads.
    MyThread mt1 = new MyThread("Child #1");
    MyThread mt2 = new MyThread("Child #2");
    MyThread mt3 = new MyThread("Child #3");
 
    do {
      Console.Write(".");
      Thread.Sleep(100);
    } while (mt1.count < 10 ||
             mt2.count < 10 ||
             mt3.count < 10);
 
    Console.WriteLine("Main thread ending.");
  }
}

listing 4
// Use IsAlive to wait for threads to end.
class MoreThreads {
  public static void Main() {
    Console.WriteLine("Main thread starting.");
 
    // Construct three threads.
    MyThread mt1 = new MyThread("Child #1");
    MyThread mt2 = new MyThread("Child #2");
    MyThread mt3 = new MyThread("Child #3");
 
    do {
      Console.Write(".");
      Thread.Sleep(100);
    } while (mt1.thrd.IsAlive &&
             mt2.thrd.IsAlive &&
             mt3.thrd.IsAlive);
 
    Console.WriteLine("Main thread ending.");
  }
}

listing 5
// Use Join().
 
using System;
using System.Threading;
 
class MyThread {
  public int count;
  public Thread thrd;
 
  public MyThread(string name) {
    count = 0;
    thrd = new Thread(this.run);
    thrd.Name = name;
    thrd.Start();
  }
 
  // Entry point of thread.
  void run() {
    Console.WriteLine(thrd.Name + " starting.");
 
    do {
      Thread.Sleep(500);
      Console.WriteLine("In " + thrd.Name +
                        ", count is " + count);
      count++;
    } while(count < 10);
 
    Console.WriteLine(thrd.Name + " terminating.");
  }
}
 
// Use Join() to wait for threads to end.
class JoinThreads {
  public static void Main() {
    Console.WriteLine("Main thread starting.");
 
    // Construct three threads.
    MyThread mt1 = new MyThread("Child #1");
    MyThread mt2 = new MyThread("Child #2");
    MyThread mt3 = new MyThread("Child #3");
 
    mt1.thrd.Join();
    Console.WriteLine("Child #1 joined.");
 
    mt2.thrd.Join();
    Console.WriteLine("Child #2 joined.");
 
    mt3.thrd.Join();
    Console.WriteLine("Child #3 joined.");
 
    Console.WriteLine("Main thread ending.");
  }
}

listing 6
// Passing an argument to the thread method.
 
using System; 
using System.Threading; 
 
class MyThread { 
  public int count; 
  public Thread thrd; 
 
  // Notice that MyThread is also pass an int value.
  public MyThread(string name, int num) { 
    count = 0; 
 
    // Explicitly invoke ParameterizedThreadStart constructor
    // for the sake of illustration.
    thrd = new Thread(new ParameterizedThreadStart(this.run));
 
    thrd.Name = name;
 
     // Here, Start() is passed num as an argument.
    thrd.Start(num); 
  } 
 
  // Notice that this version of run() has
  // a parameter of type object.
  void run(object num) { 
    Console.WriteLine(thrd.Name +
                      " starting with count of " + num); 
 
    do { 
      Thread.Sleep(500); 
      Console.WriteLine("In " + thrd.Name + 
                        ", count is " + count); 
      count++; 
    } while(count < (int) num); 
 
    Console.WriteLine(thrd.Name + " terminating."); 
  } 

 
class PassArgDemo { 
  public static void Main() { 
 
    // Notice that the iteration count is passed
    // to these two MyThread objects.
    MyThread mt = new MyThread("Child #1", 5); 
    MyThread mt2 = new MyThread("Child #1", 3); 
 
    do { 
      Thread.Sleep(100); 
    } while (mt.thrd.IsAlive | mt2.thrd.IsAlive); 
 
    Console.WriteLine("Main thread ending."); 
  } 
}

listing 7
// Demonstrate thread priorities.
 
using System;
using System.Threading;
 
class MyThread {
  public int count;
  public Thread thrd;
 
  static bool stop = false;
  static string currentName;
 
  /* Construct a new thread. Notice that this 
     constructor does not actually start the
     threads running. */
  public MyThread(string name) {
    count = 0;
    thrd = new Thread(this.run);
    thrd.Name = name;
    currentName = name;
  }
 
  // Begin execution of new thread.
  void run() {
    Console.WriteLine(thrd.Name + " starting.");
    do {
      count++;
 
      if(currentName != thrd.Name) {
        currentName = thrd.Name;
        Console.WriteLine("In " + currentName);
      }
 
    } while(stop == false && count < 1000000000);
    stop = true;
 
    Console.WriteLine(thrd.Name + " terminating.");
  }
}
 
class PriorityDemo {
  public static void Main() {
    MyThread mt1 = new MyThread("High Priority");
    MyThread mt2 = new MyThread("Low Priority");
 
    // Set the priorities.
    mt1.thrd.Priority = ThreadPriority.AboveNormal;
    mt2.thrd.Priority = ThreadPriority.BelowNormal;
 
    // Start the threads.
    mt1.thrd.Start();
    mt2.thrd.Start();
 
    mt1.thrd.Join();
    mt2.thrd.Join();
 
    Console.WriteLine();
    Console.WriteLine(mt1.thrd.Name + " thread counted to " +
                      mt1.count);
    Console.WriteLine(mt2.thrd.Name + " thread counted to " +
                      mt2.count);
  }
}

listing 8
// Use lock to synchronize access to an object. 
 
using System;
using System.Threading;
 
class SumArray { 
  int sum; 
 
  public int sumIt(int[] nums) { 
    lock(this) { // lock the entire method
      sum = 0; // reset sum 
   
      for(int i=0; i < nums.Length; i++) { 
        sum += nums[i]; 
        Console.WriteLine("Running total for " + 
               Thread.CurrentThread.Name + 
               " is " + sum); 
        Thread.Sleep(10); // allow task-switch 
      } 
      return sum;
    }
  } 
}  
 
class MyThread { 
  public Thread thrd; 
  int[] a; 
  int answer;
 
  /* Create one SumArray object for all
     instances of MyThread. */
  static SumArray sa = new SumArray(); 
 
  // Construct a new thread. 
  public MyThread(string name, int[] nums) { 
    a = nums; 
    thrd = new Thread(this.run);
    thrd.Name = name;
    thrd.Start(); // start the thread 
  } 
 
  // Begin execution of new thread. 
  void run() { 
    Console.WriteLine(thrd.Name + " starting."); 
 
    answer = sa.sumIt(a);          
 
    Console.WriteLine("Sum for " + thrd.Name + 
                       " is " + answer); 
 
    Console.WriteLine(thrd.Name + " terminating."); 
  } 

 
class Sync { 
  public static void Main() { 
    int[] a = {1, 2, 3, 4, 5}; 
 
    MyThread mt1 = new MyThread("Child #1", a); 
    MyThread mt2 = new MyThread("Child #2", a); 
 
    mt1.thrd.Join(); 
    mt2.thrd.Join(); 
  } 
}

listing 9
// Another way to use lock to synchronize access to an object. 
 
using System;
using System.Threading;
 
class SumArray { 
  int sum; 
 
  public int sumIt(int[] nums) { 
    sum = 0; // reset sum 
 
    for(int i=0; i < nums.Length; i++) { 
      sum += nums[i]; 
      Console.WriteLine("Running total for " + 
             Thread.CurrentThread.Name + 
             " is " + sum); 
      Thread.Sleep(10); // allow task-switch 
    } 
    return sum;
  } 
}  
 
class MyThread { 
  public Thread thrd; 
  int[] a; 
  int answer;
 
  /* Create one SumArray object for all
     instances of MyThread. */
  static SumArray sa = new SumArray(); 
 
  // Construct a new thread. 
  public MyThread(string name, int[] nums) { 
    a = nums; 
    thrd = new Thread(this.run);
    thrd.Name = name;
    thrd.Start(); // start the thread 
  } 
 
  // Begin execution of new thread. 
  void run() { 
    Console.WriteLine(thrd.Name + " starting."); 
 
    // Lock calls to sumIt(). 
    lock(sa) answer = sa.sumIt(a);
 
    Console.WriteLine("Sum for " + thrd.Name + 
                       " is " + answer); 
 
    Console.WriteLine(thrd.Name + " terminating."); 
  } 

 
class Sync { 
  public static void Main() { 
    int[] a = {1, 2, 3, 4, 5}; 
 
    MyThread mt1 = new MyThread("Child #1", a); 
    MyThread mt2 = new MyThread("Child #2", a); 
 
    mt1.thrd.Join(); 
    mt2.thrd.Join(); 
  } 
}

listing 10
// Use Wait() and Pulse() to create a ticking clock.
 
using System;
using System.Threading;
 
class TickTock {
 
  public void tick(bool running) {
    lock(this) {
      if(!running) { // stop the clock
        Monitor.Pulse(this); // notify any waiting threads
        return;
      }
 
      Console.Write("Tick ");
      Monitor.Pulse(this); // let tock() run
  
      Monitor.Wait(this); // wait for tock() to complete
    }
  }
 
  public void tock(bool running) {
    lock(this) {
      if(!running) { // stop the clock
        Monitor.Pulse(this); // notify any waiting threads
        return;
      }
 
      Console.WriteLine("Tock");
      Monitor.Pulse(this); // let tick() run
 
      Monitor.Wait(this); // wait for tick() to complete
    }
  }

 
class MyThread {
  public Thread thrd;
  TickTock ttOb;
 
  // Construct a new thread.
  public MyThread(string name, TickTock tt) {
    thrd = new Thread(this.run);
    ttOb = tt;
    thrd.Name = name;
    thrd.Start(); 
  }
 
  // Begin execution of new thread.
  void run() {
    if(thrd.Name == "Tick") {
      for(int i=0; i<5; i++) ttOb.tick(true);
      ttOb.tick(false);
    }
    else {
      for(int i=0; i<5; i++) ttOb.tock(true);
      ttOb.tock(false);
    }
  }
}
 
class TickingClock {
  public static void Main() {
    TickTock tt = new TickTock();
    MyThread mt1 = new MyThread("Tick", tt);
    MyThread mt2 = new MyThread("Tock", tt);
 
    mt1.thrd.Join();
    mt2.thrd.Join();
    Console.WriteLine("Clock Stopped");
  }
}

listing 11
// A non-functional version of TickTock.
class TickTock {
 
  public void tick(bool running) {
    lock(this) {
      if(!running) { // stop the clock
        return;
      }
 
      Console.Write("Tick ");
    }
  }
 
  public void tock(bool running) {
    lock(this) {
      if(!running) { // stop the clock
        return;
      }
 
      Console.WriteLine("Tock");
    }
  }
}

listing 12
// Use MethodImplAttribute to synchronize a method.
 
using System;
using System.Threading;
using System.Runtime.CompilerServices;
 
// Rewrite of TickTock to use MethodImplOptions.Synchronized.
class TickTock {
 
  /* The following attribute synchronizes the entire
     tick() method. */
  [MethodImplAttribute(MethodImplOptions.Synchronized)]
  public void tick(bool running) {
    if(!running) { // stop the clock
      Monitor.Pulse(this); // notify any waiting threads
      return;
    }
 
    Console.Write("Tick ");
    Monitor.Pulse(this); // let tock() run
  
    Monitor.Wait(this); // wait for tock() to complete
  }
 
 
  /* The following attribute synchronizes the entire
     tock() method. */
  [MethodImplAttribute(MethodImplOptions.Synchronized)]
  public void tock(bool running) {
    if(!running) { // stop the clock
      Monitor.Pulse(this); // notify any waiting threads
      return;
    }
 
    Console.WriteLine("Tock");
    Monitor.Pulse(this); // let tick() run
 
    Monitor.Wait(this); // wait for tick() to complete
  }

 
class MyThread {
  public Thread thrd;
  TickTock ttOb;
 
  // Construct a new thread.
  public MyThread(string name, TickTock tt) {
    thrd = new Thread(this.run);
    ttOb = tt;
    thrd.Name = name;
    thrd.Start(); 
  }
 
  // Begin execution of new thread.
  void run() {
    if(thrd.Name == "Tick") {
      for(int i=0; i<5; i++) ttOb.tick(true);
      ttOb.tick(false);
    }
    else {
      for(int i=0; i<5; i++) ttOb.tock(true);
      ttOb.tock(false);
    }
  }
}
 
class TickingClock {
  public static void Main() {
    TickTock tt = new TickTock();
    MyThread mt1 = new MyThread("Tick", tt);
    MyThread mt2 = new MyThread("Tock", tt);
 
    mt1.thrd.Join();
    mt2.thrd.Join();
    Console.WriteLine("Clock Stopped");
  }
}

listing 13
// Use a Mutex.
 
using System; 
using System.Threading; 
 
// This class contains a shared resource (count),
// and a mutex (mtx) to control access to it. 
class SharedRes {
  public static int count = 0;
  public static Mutex mtx = new Mutex();
}
 
// This thread increments SharedRes.count.
class IncThread { 
  int num;
  public Thread thrd; 
 
  public IncThread(string name, int n) { 
    thrd = new Thread(this.run); 
    num = n;
    thrd.Name = name; 
    thrd.Start(); 
  } 
 
  // Entry point of thread. 
  void run() { 
 
    Console.WriteLine(thrd.Name + " is waiting for the mutex.");
 
    // Acquire the Mutex.
    SharedRes.mtx.WaitOne();
 
    Console.WriteLine(thrd.Name + " acquires the mutex.");
 
    do { 
      Thread.Sleep(500); 
      SharedRes.count++; 
      Console.WriteLine("In " + thrd.Name + 
                        ", SharedRes.count is " + SharedRes.count); 
      num--;
    } while(num > 0); 
 
    Console.WriteLine(thrd.Name + " releases the mutex.");  
 
    // Release the Mutex.
    SharedRes.mtx.ReleaseMutex();
  } 

 
// This thread decrements SharedRes.count.
class DecThread { 
  int num;
  public Thread thrd; 
 
  public DecThread(string name, int n) { 
    thrd = new Thread(new ThreadStart(this.run)); 
    num = n;
    thrd.Name = name; 
    thrd.Start(); 
  } 
 
  // Entry point of thread. 
  void run() { 
 
    Console.WriteLine(thrd.Name + " is waiting for the mutex.");
 
    // Acquire the Mutex.
    SharedRes.mtx.WaitOne();
 
    Console.WriteLine(thrd.Name + " acquires the mutex.");
 
    do { 
      Thread.Sleep(500); 
      SharedRes.count--; 
      Console.WriteLine("In " + thrd.Name + 
                        ", SharedRes.count is " + SharedRes.count); 
      num--;
    } while(num > 0); 
 
    Console.WriteLine(thrd.Name + " releases the mutex."); 
 
    // Release the Mutex.
    SharedRes.mtx.ReleaseMutex();
  } 

 
class MutexDemo { 
  public static void Main() { 
 
    // Construct three threads. 
    IncThread mt1 = new IncThread("Increment Thread", 5); 
    DecThread mt2 = new DecThread("Decrement Thread", 5); 
 
    mt1.thrd.Join();
    mt2.thrd.Join();
  } 
}

listing 14
// Use a Semaphore
 
using System; 
using System.Threading; 
 
// This thread allows only two instances of itself
// to run at any one time.
class MyThread { 
  public Thread thrd;
 
  // This creates a semaphore that allows up to 2
  // permits to be granted and that initially has
  // two permits available.
  static Semaphore sem = new Semaphore(2, 2);
 
  public MyThread(string name) { 
    thrd = new Thread(this.run); 
    thrd.Name = name; 
    thrd.Start(); 
  } 
 
  // Entry point of thread. 
  void run() { 
 
    Console.WriteLine(thrd.Name + " is waiting for a permit.");
 
    sem.WaitOne();
 
    Console.WriteLine(thrd.Name + " acquires a permit.");
 
    for(char ch='A'; ch < 'D'; ch++) {
      Console.WriteLine(thrd.Name + " : " + ch + " ");
      Thread.Sleep(500); 
    }
 
    Console.WriteLine(thrd.Name + " releases a permit.");
 
    // Release the semaphore.
    sem.Release();
  } 

 
 
class SemaphoreDemo { 
  public static void Main() { 
 
    // Construct three threads. 
    MyThread mt1 = new MyThread("Thread #1"); 
    MyThread mt2 = new MyThread("Thread #2"); 
    MyThread mt3 = new MyThread("Thread #3"); 
 
    mt1.thrd.Join();
    mt2.thrd.Join();
    mt3.thrd.Join();
  } 
}

listing 15
// Use a manual event object. 
  
using System;  
using System.Threading;  
 
// This thread signals the event passed to its constructor. 
class MyThread {  
  public Thread thrd; 
  ManualResetEvent mre; 
  
  public MyThread(string name, ManualResetEvent evt) {  
    thrd = new Thread(this.run);  
    thrd.Name = name; 
    mre = evt; 
    thrd.Start();  
  }  
  
  // Entry point of thread.  
  void run() {  
    Console.WriteLine("Inside thread " + thrd.Name); 
 
    for(int i=0; i<5; i++) { 
      Console.WriteLine(thrd.Name); 
      Thread.Sleep(500); 
    } 
 
    Console.WriteLine(thrd.Name + " Done!"); 
 
    // Signal the event.
    mre.Set();
  }  
}  
  
class ManualEventDemo {  
  public static void Main() {  
    ManualResetEvent evtObj = new ManualResetEvent(false); 
 
    MyThread mt1 = new MyThread("Event Thread 1", evtObj);  

    Console.WriteLine("Main thread waiting for event.");

    // Wait for signaled event.
    evtObj.WaitOne();

    Console.WriteLine("Main thread received first event.");


    // Reset the event.
    evtObj.Reset();


    mt1 = new MyThread("Event Thread 2", evtObj);  

    // Wait for signaled event.
    evtObj.WaitOne();

    Console.WriteLine("Main thread received second event.");

  }  
}


listing 16
// Use Interlocked operations.
 
using System; 
using System.Threading; 
 
// A shared resource.
class SharedRes {
  public static int count = 0;
}
 
// This thread increments SharedRes.count.
class IncThread { 
  public Thread thrd;
 
  public IncThread(string name) { 
    thrd = new Thread(this.run); 
    thrd.Name = name;
    thrd.Start(); 
  } 
 
  // Entry point of thread. 
  void run() { 
 
    for(int i=0; i<5; i++) {
      Interlocked.Increment(ref SharedRes.count);
      Console.WriteLine(thrd.Name + " count is " + SharedRes.count);
    }
  } 

 
// This thread decrements SharedRes.count.
class DecThread { 
  public Thread thrd;
 
  public DecThread(string name) { 
    thrd = new Thread(this.run); 
    thrd.Name = name;
    thrd.Start(); 
  } 
 
  // Entry point of thread. 
  void run() { 
 
    for(int i=0; i<5; i++) {
      Interlocked.Decrement(ref SharedRes.count);
      Console.WriteLine(thrd.Name + " count is " + SharedRes.count);
    }
  } 

 
class InterdlockedDemo { 
  public static void Main() { 
 
    // Construct two threads. 
    IncThread mt1 = new IncThread("Increment Thread"); 
    DecThread mt2 = new DecThread("Decrement Thread"); 
 
    mt1.thrd.Join();
    mt2.thrd.Join();
  } 
}

listing 17
// Stopping a thread.
 
using System;
using System.Threading;
 
class MyThread { 
  public Thread thrd; 
   
  public MyThread(string name) { 
    thrd = new Thread(this.run);
    thrd.Name = name;
    thrd.Start(); 
  } 
 
  // This is the entry point for thread. 
  void run() { 
    Console.WriteLine(thrd.Name + " starting.");
 
    for(int i = 1; i <= 1000; i++) { 
      Console.Write(i + " "); 
      if((i%10)==0) {
        Console.WriteLine();
        Thread.Sleep(250);
      }
    }
    Console.WriteLine(thrd.Name + " exiting."); 
  } 
}
 
class StopDemo { 
  public static void Main() { 
    MyThread mt1 = new MyThread("My Thread"); 
 
    Thread.Sleep(1000); // let child thread start executing
 
    Console.WriteLine("Stopping thread."); 
    mt1.thrd.Abort();
 
    mt1.thrd.Join(); // wait for thread to terminate
 
    Console.WriteLine("Main thread terminating."); 
  } 
}

listing 18
// Using Abort(object).
 
using System;
using System.Threading;
 
class MyThread { 
  public Thread thrd; 
   
  public MyThread(string name) { 
    thrd = new Thread(this.run);
    thrd.Name = name;
    thrd.Start(); 
  } 
 
  // This is the entry point for thread. 
  void run() { 
    try {
      Console.WriteLine(thrd.Name + " starting.");
 
      for(int i = 1; i <= 1000; i++) { 
        Console.Write(i + " "); 
        if((i%10)==0) {
          Console.WriteLine();
          Thread.Sleep(250);
        }
      }
      Console.WriteLine(thrd.Name + " exiting normally."); 
    } catch(ThreadAbortException exc) {
      Console.WriteLine("Thread aborting, code is " +
                         exc.ExceptionState);
    }
  } 
}
 
class UseAltAbort { 
  public static void Main() { 
    MyThread mt1 = new MyThread("My Thread"); 
 
    Thread.Sleep(1000); // let child thread start executing
 
    Console.WriteLine("Stopping thread."); 
    mt1.thrd.Abort(100);
 
    mt1.thrd.Join(); // wait for thread to terminate
 
    Console.WriteLine("Main thread terminating."); 
  } 
}

listing 19
// Using ResetAbort().
 
using System;
using System.Threading;
 
class MyThread { 
  public Thread thrd; 
   
  public MyThread(string name) { 
    thrd = new Thread(this.run);
    thrd.Name = name;
    thrd.Start(); 
  } 
 
  // This is the entry point for thread. 
  void run() { 
    Console.WriteLine(thrd.Name + " starting.");
 
    for(int i = 1; i <= 1000; i++) { 
      try {
        Console.Write(i + " "); 
        if((i%10)==0) {
          Console.WriteLine();
          Thread.Sleep(250);
        }
      } catch(ThreadAbortException exc) {
        if((int)exc.ExceptionState == 0) {
          Console.WriteLine("Abort Cancelled! Code is " +
                             exc.ExceptionState);
          Thread.ResetAbort();
        }
        else 
          Console.WriteLine("Thread aborting, code is " +
                             exc.ExceptionState);
      }
    }
    Console.WriteLine(thrd.Name + " exiting normally."); 
  }
}
 
class ResetAbort { 
  public static void Main() { 
    MyThread mt1 = new MyThread("My Thread"); 
 
    Thread.Sleep(1000); // let child thread start executing
 
    Console.WriteLine("Stopping thread."); 
    mt1.thrd.Abort(0); // this won't stop the thread
 
    Thread.Sleep(1000); // let child execute a bit longer
 
    Console.WriteLine("Stopping thread."); 
    mt1.thrd.Abort(100); // this will stop the thread
 
    mt1.thrd.Join(); // wait for thread to terminate
 
    Console.WriteLine("Main thread terminating."); 
  } 
}

listing 20
// Control the main thread.
 
using System;
using System.Threading;
 
class UseMain {
  public static void Main() {
    Thread thrd;
 
    // Get the main thread.
    thrd = Thread.CurrentThread;
 
    // Display main thread's name.
    if(thrd.Name == null)
      Console.WriteLine("Main thread has no name.");
    else
      Console.WriteLine("Main thread is called: " + thrd.Name);
 
    // Display main thread's priority.
    Console.WriteLine("Priority: " + thrd.Priority);
 
    Console.WriteLine();
 
    // Set the name and priority.
    Console.WriteLine("Setting name and priority.\n");
    thrd.Name = "Main Thread";
    thrd.Priority = ThreadPriority.AboveNormal;
 
    Console.WriteLine("Main thread is now called: " +
                       thrd.Name);
 
    Console.WriteLine("Priority is now: " +
                       thrd.Priority);
  }
}

listing 21
// Starting a new process.
 
using System;
using System.Diagnostics;
 
class StartProcess { 
  public static void Main() { 
    Process newProc = Process.Start("wordpad.exe");
 
    Console.WriteLine("New process started.");
 
    newProc.WaitForExit();
 
    newProc.Close(); // free resources
 
    Console.WriteLine("New process ended.");
  } 
}

listing 1
// Demonstrate ArrayList.
 
using System;
using System.Collections;
 
class ArrayListDemo {
  public static void Main() {
    // create an array list
    ArrayList al = new ArrayList();
    
    Console.WriteLine("Initial number of elements: " +
                       al.Count);
 
    Console.WriteLine();
 
    Console.WriteLine("Adding 6 elements");
    // Add elements to the array list
    al.Add('C');
    al.Add('A');
    al.Add('E');
    al.Add('B');
    al.Add('D');
    al.Add('F');
 
    Console.WriteLine("Number of elements: " +
                       al.Count);
 
    // Display the array list using array indexing.
    Console.Write("Current contents: ");
    for(int i=0; i < al.Count; i++)
      Console.Write(al[i] + " ");
    Console.WriteLine("\n");
 
    Console.WriteLine("Removing 2 elements");
    // Remove elements from the array list.
    al.Remove('F');
    al.Remove('A');
 
    Console.WriteLine("Number of elements: " +
                       al.Count);
 
    // Use foreach loop to display the list.
    Console.Write("Contents: ");
    foreach(char c in al)
      Console.Write(c + " ");
    Console.WriteLine("\n");
 
    Console.WriteLine("Adding 20 more elements");
    // Add enough elements to force al to grow.
    for(int i=0; i < 20; i++)
      al.Add((char)('a' + i));
    Console.WriteLine("Current capacity: " +
                       al.Capacity);
    Console.WriteLine("Number of elements after adding 20: " +
                       al.Count);
    Console.Write("Contents: ");
    foreach(char c in al)
      Console.Write(c + " ");
    Console.WriteLine("\n");
 
    // Change contents using array indexing.
    Console.WriteLine("Change first three elements");
    al[0] = 'X';
    al[1] = 'Y';
    al[2] = 'Z';
    Console.Write("Contents: ");
    foreach(char c in al)
      Console.Write(c + " ");
    Console.WriteLine();
  }
}

listing 2
// Sort and search an ArrayList.
 
using System;
using System.Collections;
 
class SortSearchDemo {
  public static void Main() {
    // create an array list
    ArrayList al = new ArrayList();
    
    // Add elements to the array list
    al.Add(55);
    al.Add(43);
    al.Add(-4);
    al.Add(88);
    al.Add(3);
    al.Add(19);
 
    Console.Write("Original contents: ");
    foreach(int i in al)
      Console.Write(i + " ");
    Console.WriteLine("\n");
 
    // Sort
    al.Sort();
 
    // Use foreach loop to display the list.
    Console.Write("Contents after sorting: ");
    foreach(int i in al)
      Console.Write(i + " ");
    Console.WriteLine("\n");
 
    Console.WriteLine("Index of 43 is " +
                      al.BinarySearch(43));
  }
}

listing 3
// Convert an ArrayList into an array.
 
using System;
using System.Collections;
 
class ArrayListToArray {
  public static void Main() {
    ArrayList al = new ArrayList();
    
    // Add elements to the array list.
    al.Add(1);
    al.Add(2);
    al.Add(3);
    al.Add(4);
 
    Console.Write("Contents: ");
    foreach(int i in al)
      Console.Write(i + " ");
    Console.WriteLine();
 
    // Get the array.
    int[] ia = (int[]) al.ToArray(typeof(int));
    int sum = 0;
 
    // sum the array
    for(int i=0; i<ia.Length; i++)
      sum += ia[i];
 
    Console.WriteLine("Sum is: " + sum);
  }
}

listing 4
// Demonstrate Hashtable.
 
using System;
using System.Collections;
 
class HashtableDemo {
  public static void Main() {
    // Create a hash table.
    Hashtable ht = new Hashtable();
    
    // Add elements to the table
    ht.Add("house", "Dwelling");
    ht.Add("car", "Means of transport");
    ht.Add("book", "Collection of printed words");
    ht.Add("apple", "Edible fruit");
 
    // Can also add by using the indexer.
    ht["tractor"] = "Farm implement";
 
    // Get a collection of the keys.
    ICollection c = ht.Keys;
 
    // Use the keys to obtain the values.
    foreach(string str in c)
      Console.WriteLine(str + ": " + ht[str]);
  }
}

listing 5
// Demonstrate a SortedList.
 
using System;
using System.Collections;
 
class SLDemo {
  public static void Main() {
    // Create a sorted SortedList.
    SortedList sl = new SortedList();
    
    // Add elements to the table
    sl.Add("house", "Dwelling");
    sl.Add("car", "Means of transport");
    sl.Add("book", "Collection of printed words");
    sl.Add("apple", "Edible fruit");
 
    // Can also add by using the indexer.
    sl["tractor"] = "Farm implement";
 
    // Get a collection of the keys.
    ICollection c = sl.Keys;
 
    // Use the keys to obtain the values.
    Console.WriteLine("Contents of list via indexer.");
    foreach(string str in c)
      Console.WriteLine(str + ": " + sl[str]);
 
    Console.WriteLine();
 
    // Display list using integer indexes.
    Console.WriteLine("Contents by integer indexes.");
    for(int i=0; i<sl.Count; i++)
      Console.WriteLine(sl.GetByIndex(i));
 
    Console.WriteLine();
 
    // Show integer indexes of entries.
    Console.WriteLine("Integer indexes of entries.");
    foreach(string str in c)
      Console.WriteLine(str + ": " + sl.IndexOfKey(str));
  }
}

listing 6
// Demonstrate the Stack class.
 
using System;
using System.Collections;
 
class StackDemo {
  static void showPush(Stack st, int a) {
    st.Push(a);
    Console.WriteLine("Push(" + a + ")");
 
    Console.Write("stack: ");
    foreach(int i in st)
      Console.Write(i + " ");
 
    Console.WriteLine();        
  }
 
  static void showPop(Stack st) {
    Console.Write("Pop -> ");
    int a = (int) st.Pop();
    Console.WriteLine(a);
 
    Console.Write("stack: ");
    foreach(int i in st)
      Console.Write(i + " ");
 
    Console.WriteLine();        
  }
 
  public static void Main() {
    Stack st = new Stack();
 
    foreach(int i in st)
      Console.Write(i + " ");
 
    Console.WriteLine();        
 
    showPush(st, 22);
    showPush(st, 65);
    showPush(st, 91);
    showPop(st);
    showPop(st);
    showPop(st);
 
    try {
      showPop(st);
    } catch (InvalidOperationException) {
      Console.WriteLine("Stack empty.");
    }
  }
}

listing 7
// Demonstrate the Queue class.
 
using System;
using System.Collections;
 
class QueueDemo {
  static void showEnq(Queue q, int a) {
    q.Enqueue(a);
    Console.WriteLine("Enqueue(" + a + ")");
 
    Console.Write("queue: ");
    foreach(int i in q)
      Console.Write(i + " ");
 
    Console.WriteLine();        
  }
 
  static void showDeq(Queue q) {
    Console.Write("Dequeue -> ");
    int a = (int) q.Dequeue();
    Console.WriteLine(a);
 
    Console.Write("queue: ");
    foreach(int i in q)
      Console.Write(i + " ");
 
    Console.WriteLine();        
  }
 
  public static void Main() {
    Queue q = new Queue();
 
    foreach(int i in q)
      Console.Write(i + " ");
 
    Console.WriteLine();        
 
    showEnq(q, 22);
    showEnq(q, 65);
    showEnq(q, 91);
    showDeq(q);
    showDeq(q);
    showDeq(q);
 
    try {
      showDeq(q);
    } catch (InvalidOperationException) {
      Console.WriteLine("Queue empty.");
    }
  }
}

listing 8
// Demonstrate BitArray.
 
using System;
using System.Collections;
 
class BADemo {
  public static void showbits(string rem,
                         BitArray bits) {
    Console.WriteLine(rem);
    for(int i=0; i < bits.Count; i++)
      Console.Write("{0, -6} ", bits[i]);
    Console.WriteLine("\n");
  }
 
  public static void Main() {
    BitArray ba = new BitArray(8);
    byte[] b = { 67 };
    BitArray ba2 = new BitArray(b);
    
    showbits("Original contents of ba:", ba);
      
    ba = ba.Not();
 
    showbits("Contents of ba after Not:", ba);
 
    showbits("Contents of ba2:", ba2);
 
    BitArray ba3 = ba.Xor(ba2);
 
    showbits("Result of ba XOR ba2:", ba3);
  }
}

listing 9
// Demonstrate List<T>.
 
using System; 
using System.Collections.Generic; 
 
class GenListDemo { 
  public static void Main() { 
    // Create a list.
    List<char> lst = new List<char>(); 
     
    Console.WriteLine("Initial number of elements: " + 
                       lst.Count); 
 
    Console.WriteLine(); 
 
    Console.WriteLine("Adding 6 elements"); 
    // Add elements to the array list 
    lst.Add('C'); 
    lst.Add('A'); 
    lst.Add('E'); 
    lst.Add('B'); 
    lst.Add('D'); 
    lst.Add('F'); 
 
    Console.WriteLine("Number of elements: " + 
                       lst.Count); 
 
    // Display the array list using array indexing. 
    Console.Write("Current contents: "); 
    for(int i=0; i < lst.Count; i++) 
      Console.Write(lst[i] + " "); 
    Console.WriteLine("\n"); 
 
    Console.WriteLine("Removing 2 elements"); 
    // Remove elements from the array list. 
    lst.Remove('F'); 
    lst.Remove('A'); 
 
    Console.WriteLine("Number of elements: " + 
                       lst.Count); 
 
    // Use foreach loop to display the list. 
    Console.Write("Contents: "); 
    foreach(char c in lst) 
      Console.Write(c + " "); 
    Console.WriteLine("\n"); 
 
    Console.WriteLine("Adding 20 more elements"); 
    // Add enough elements to force lst to grow. 
    for(int i=0; i < 20; i++) 
      lst.Add((char)('a' + i)); 
    Console.WriteLine("Current capacity: " + 
                       lst.Capacity); 
    Console.WriteLine("Number of elements after adding 20: " + 
                       lst.Count); 
    Console.Write("Contents: "); 
    foreach(char c in lst) 
      Console.Write(c + " "); 
    Console.WriteLine("\n"); 
 
    // Change contents using array indexing. 
    Console.WriteLine("Change first three elements"); 
    lst[0] = 'X'; 
    lst[1] = 'Y'; 
    lst[2] = 'Z'; 
 
    Console.Write("Contents: "); 
    foreach(char c in lst) 
      Console.Write(c + " "); 
    Console.WriteLine(); 
 
    // Because of generic type-safety, 
    // the following line is illegal.
//    lst.Add(99); // Error, not a char!
  } 
}

listing 10
// Demonstrate LinkedList<T>.
 
using System; 
using System.Collections.Generic; 
 
class GenLinkedListDemo { 
  public static void Main() { 
    // Create an linked list.
    LinkedList<char> ll = new LinkedList<char>(); 
     
    Console.WriteLine("Initial number of elements: " + 
                       ll.Count); 
 
    Console.WriteLine(); 
 
    Console.WriteLine("Adding 5 elements."); 
    // Add elements to the linked list 
    ll.AddFirst('A'); 
    ll.AddFirst('B'); 
    ll.AddFirst('C'); 
    ll.AddFirst('D'); 
    ll.AddFirst('E'); 
 
    Console.WriteLine("Number of elements: " + 
                       ll.Count); 
 
    // Display the linked list by manually walking
    // through the list.
    LinkedListNode<char> node;
 
    Console.Write("Display contents by following links: ");
    for(node = ll.First; node != null; node = node.Next) 
      Console.Write(node.Value + " "); 
 
    Console.WriteLine("\n"); 
 
    //Display the linked list by use of a foreach loop.
    Console.Write("Display contents with foreach loop: ");
    foreach(char ch in ll)
      Console.Write(ch + " "); 
 
    Console.WriteLine("\n"); 
 
    // Display the list backwards by manually walking
    // from last to first.
    Console.Write("Follow links backwards: ");
      for(node = ll.Last; node != null; node = node.Previous) 
      Console.Write(node.Value + " "); 
 
    Console.WriteLine("\n"); 
 
    // Remove two elements.
    Console.WriteLine("Removing 2 elements."); 
    // Remove elements from the linked list. 
    ll.Remove('C'); 
    ll.Remove('A'); 
 
    Console.WriteLine("Number of elements: " + 
                       ll.Count); 
 
    // Use foreach loop to display the modified list. 
    Console.Write("Contents after deletion: "); 
    foreach(char ch in ll) 
      Console.Write(ch + " "); 
 
    Console.WriteLine("\n"); 
 
    // Add three elements to the end of the list.
    ll.AddLast('X');
    ll.AddLast('Y');
    ll.AddLast('Z');
 
    Console.Write("Contents after addition to end: "); 
    foreach(char ch in ll) 
      Console.Write(ch + " "); 
 
    Console.WriteLine("\n"); 
  } 
}

listing 11
// Demonstrate the generic Dictionary<TK, TV> class.
 
using System; 
using System.Collections.Generic; 
 
class GenDictionaryDemo { 
  public static void Main() { 
    // Create a Dictionary that holds employee
    // names and their corresponding salaries.
    Dictionary<string, double> dict =
      new Dictionary<string, double>(); 
     
    // Add elements to the collection.
    dict.Add("Butler, John", 73000); 
    dict.Add("Swartz, Sarah", 59000); 
    dict.Add("Pyke, Thomas", 45000); 
    dict.Add("Frank, Ed", 99000); 
 
    // Get a collection of the keys (names).
    ICollection<string> c = dict.Keys; 
 
    // Use the keys to obtain the values (salares).
    foreach(string str in c) 
      Console.WriteLine("{0}, Salary: {1:C}", str, dict[str]); 
  } 
}

listing 12
// Demonstrate the generic SortedDictionary<TK, TV> class.
 
using System; 
using System.Collections.Generic; 
 
class GenSortedDictionaryDemo { 
  public static void Main() { 
    // Create a Dictionary that holds employee
    // names and their corresponding salaries.
    SortedDictionary<string, double> dict =
      new SortedDictionary<string, double>(); 
     
    // Add elements to the collection.
    dict.Add("Butler, John", 73000); 
    dict.Add("Swartz, Sarah", 59000); 
    dict.Add("Pyke, Thomas", 45000); 
    dict.Add("Frank, Ed", 99000); 
 
    // Get a collection of the keys (names).
    ICollection<string> c = dict.Keys; 
 
    // Use the keys to obtain the values (salares).
    foreach(string str in c) 
      Console.WriteLine("{0}, Salary: {1:C}", str, dict[str]); 
  } 
}

listing 13
// Demonstrate a SortedList<TK, TV>. 
 
using System; 
using System.Collections.Generic; 
 
class GenSLDemo { 
  public static void Main() { 
    // Create a sorted SortedList<T> for
    // employee names and salaries.
    SortedList<string, double> sl = 
      new SortedList<string, double>(); 
      
    // Add elements to the collection.
    sl.Add("Butler, John", 73000); 
    sl.Add("Swartz, Sarah", 59000); 
    sl.Add("Pyke, Thomas", 45000); 
    sl.Add("Frank, Ed", 99000); 
 
    // Get a collection of the keys. 
    ICollection<string> c = sl.Keys; 
 
    // Use the keys to obtain the values. 
    foreach(string str in c) 
      Console.WriteLine("{0}, Salary: {1:C}", str, sl[str]); 
 
    Console.WriteLine(); 
  } 
}

listing 14
// Demonstrate the Stack<T> class. 
 
using System; 
using System.Collections.Generic; 
  
class GenStackDemo { 
  public static void Main() { 
    Stack<string> st = new Stack<string>(); 
 
    st.Push("One"); 
    st.Push("Two"); 
    st.Push("Three"); 
    st.Push("Four"); 
    st.Push("Five"); 
 
    while(st.Count > 0) {
      string str = st.Pop();
      Console.Write(str + " ");
    }
 
    Console.WriteLine(); 
  } 
}

listing 15
// Demonstrate the Queue<T> class. 
 
using System; 
using System.Collections.Generic; 
  
class GenQueueDemo { 
  public static void Main() { 
    Queue<double> q = new Queue<double>(); 
 
    q.Enqueue(98.6); 
    q.Enqueue(212.0); 
    q.Enqueue(32.0); 
    q.Enqueue(3.1416); 
 
    double sum = 0.0;
    Console.Write("Queue contents: ");
    while(q.Count > 0) {
      double val = q.Dequeue();
      Console.Write(val + " ");
      sum += val;
    }
 
    Console.WriteLine("\nTotal is " + sum); 
  } 
}

listing 16
// A simple inventory example.
 
using System;
using System.Collections;
 
class Inventory {
  string name;
  double cost;
  int onhand;
 
  public Inventory(string n, double c, int h) {
    name = n;
    cost = c;
    onhand = h;
  }
 
  public override string ToString() {
    return
      String.Format("{0,-10}Cost: {1,6:C}  On hand: {2}",
                    name, cost, onhand);
  }
}
 
class InventoryList {
  public static void Main() {
    ArrayList inv = new ArrayList();
    
    // Add elements to the list
    inv.Add(new Inventory("Pliers", 5.95, 3));
    inv.Add(new Inventory("Wrenches", 8.29, 2));   
    inv.Add(new Inventory("Hammers", 3.50, 4));
    inv.Add(new Inventory("Drills", 19.88, 8));
 
    Console.WriteLine("Inventory list:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
  }
}

listing 17
// Store Inventory Objects in a List<T> collection.
 
using System;
using System.Collections.Generic;
 
class Inventory {
  string name;
  double cost;
  int onhand;
 
  public Inventory(string n, double c, int h) {
    name = n;
    cost = c;
    onhand = h;
  }
 
  public override string ToString() {
    return
      String.Format("{0,-10}Cost: {1,6:C}  On hand: {2}",
                    name, cost, onhand);
  }
}
 
class TypeSafeInventoryList {
  public static void Main() {
    List<Inventory> inv = new List<Inventory>();
    
    // Add elements to the list
    inv.Add(new Inventory("Pliers", 5.95, 3));
    inv.Add(new Inventory("Wrenches", 8.29, 2));   
    inv.Add(new Inventory("Hammers", 3.50, 4));
    inv.Add(new Inventory("Drills", 19.88, 8));
 
    Console.WriteLine("Inventory list:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
  }
}

listing 18
// Implement IComparable.
 
using System;
using System.Collections;
 
// Implement the non-generic IComparable interface.
class Inventory : IComparable {
  string name;
  double cost;
  int onhand;
 
  public Inventory(string n, double c, int h) {
    name = n;
    cost = c;
    onhand = h;
  }
 
  public override string ToString() {
    return
      String.Format("{0,-10}Cost: {1,6:C}  On hand: {2}",
                    name, cost, onhand);
  }
 
  // Implement the IComparable interface.
  public int CompareTo(object obj) {
    Inventory b;
    b = (Inventory) obj;
    return name.CompareTo(b.name);
  }
}
 
class IComparableDemo {
  public static void Main() {
    ArrayList inv = new ArrayList();
    
    // Add elements to the list
    inv.Add(new Inventory("Pliers", 5.95, 3));
    inv.Add(new Inventory("Wrenches", 8.29, 2));   
    inv.Add(new Inventory("Hammers", 3.50, 4));
    inv.Add(new Inventory("Drills", 19.88, 8));
 
    Console.WriteLine("Inventory list before sorting:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
    Console.WriteLine();
 
    // Sort the list.
    inv.Sort();
 
    Console.WriteLine("Inventory list after sorting:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
  }
}

listing 19
// Implement IComparable<T>.
 
using System;
using System.Collections.Generic;
 
// Implement the generic IComparable<T> interface.
class Inventory : IComparable<Inventory> {
  string name;
  double cost;
  int onhand;
 
  public Inventory(string n, double c, int h) {
    name = n;
    cost = c;
    onhand = h;
  }
 
  public override string ToString() {
    return
      String.Format("{0,-10}Cost: {1,6:C}  On hand: {2}",
                    name, cost, onhand);
  }
 
  // Implement the IComparable<T> interface.
  public int CompareTo(Inventory obj) {
    return name.CompareTo(obj.name);
  }
 
}
 
class GenericIComparableDemo {
  public static void Main() {
    List<Inventory> inv = new List<Inventory>();
    
    // Add elements to the list
    inv.Add(new Inventory("Pliers", 5.95, 3));
    inv.Add(new Inventory("Wrenches", 8.29, 2));   
    inv.Add(new Inventory("Hammers", 3.50, 4));
    inv.Add(new Inventory("Drills", 19.88, 8));
 
    Console.WriteLine("Inventory list before sorting:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
    Console.WriteLine();
 
    // Sort the list.
    inv.Sort();
 
    Console.WriteLine("Inventory list after sorting:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
  }
}

listing 20
// Use IComparer.
 
using System;
using System.Collections;
 
// Create an IComparer for Inventory objects.
class CompInv : IComparer {
  // Implement the IComparable interface.
  public int Compare(object obj1, object obj2) {
    Inventory a, b;
    a = (Inventory) obj1;
    b = (Inventory) obj2;
    return a.name.CompareTo(b.name);
  }
}
 
class Inventory {
  public string name;
  double cost;
  int onhand;
 
  public Inventory(string n, double c, int h) {
    name = n;
    cost = c;
    onhand = h;
  }
 
  public override string ToString() {
    return
      String.Format("{0,-10}Cost: {1,6:C}  On hand: {2}",
                    name, cost, onhand);
  }
}
 
class IComparerDemo {
  public static void Main() {
    CompInv comp = new CompInv();
    ArrayList inv = new ArrayList();
    
    // Add elements to the list
    inv.Add(new Inventory("Pliers", 5.95, 3));
    inv.Add(new Inventory("Wrenches", 8.29, 2));   
    inv.Add(new Inventory("Hammers", 3.50, 4));
    inv.Add(new Inventory("Drills", 19.88, 8));
 
    Console.WriteLine("Inventory list before sorting:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
    Console.WriteLine();
 
    // Sort the list using an IComparer.
    inv.Sort(comp);
 
    Console.WriteLine("Inventory list after sorting:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
  }
}

listing 21
// Use IComparer<T>.
 
using System;
using System.Collections.Generic;
 
// Create an IComparer<T> for Inventory objects.
class CompInv<T> : IComparer<T> where T : Inventory {
 
  // Implement the IComparer<T> interface.
  public int Compare(T obj1, T obj2) {
    return obj1.name.CompareTo(obj2.name);
  }
 
}
 
class Inventory {
  public string name;
  double cost;
  int onhand;
 
  public Inventory(string n, double c, int h) {
    name = n;
    cost = c;
    onhand = h;
  }
 
  public override string ToString() {
    return
      String.Format("{0,-10}Cost: {1,6:C}  On hand: {2}",
                    name, cost, onhand);
  }
}
 
class GenericIComparerDemo {
  public static void Main() {
    CompInv<Inventory> comp = new CompInv<Inventory>();
    List<Inventory> inv = new List<Inventory>();
    
    // Add elements to the list
    inv.Add(new Inventory("Pliers", 5.95, 3));
    inv.Add(new Inventory("Wrenches", 8.29, 2));   
    inv.Add(new Inventory("Hammers", 3.50, 4));
    inv.Add(new Inventory("Drills", 19.88, 8));
 
    Console.WriteLine("Inventory list before sorting:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
    Console.WriteLine();
 
    // Sort the list using an IComparer.
    inv.Sort(comp);
 
    Console.WriteLine("Inventory list after sorting:");
    foreach(Inventory i in inv) {
      Console.WriteLine("   " + i);
    }
  }
}

listing 22
// Demonstrate an enumerator.
 
using System;
using System.Collections;
 
class EnumeratorDemo { 
  public static void Main() {
    ArrayList list = new ArrayList(1);
 
    for(int i=0; i < 10; i++)
      list.Add(i);
 
    // Use enumerator to access list.
    IEnumerator etr = list.GetEnumerator();
    while(etr.MoveNext()) 
      Console.Write(etr.Current + " ");
 
    Console.WriteLine();
 
    // Re杄numerate the list.
    etr.Reset();
    while(etr.MoveNext()) 
      Console.Write(etr.Current + " ");
 
    Console.WriteLine();
  }
}

listing 23
// Demonstrate IDictionaryEnumerator.
 
using System;
using System.Collections;
 
class IDicEnumDemo {
  public static void Main() {
    // Create a hash table.
    Hashtable ht = new Hashtable();
    
    // Add elements to the table
    ht.Add("Tom", "555?456");
    ht.Add("Mary", "555?876");
    ht.Add("Todd", "555?452");
    ht.Add("Ken", "555?756");
 
    // Demonstrate enumerator
    IDictionaryEnumerator etr = ht.GetEnumerator();
    Console.WriteLine("Display info using Entry.");
    while(etr.MoveNext()) 
     Console.WriteLine(etr.Entry.Key + ": " + 
                       etr.Entry.Value);
 
    Console.WriteLine();
 
    Console.WriteLine("Display info using Key and Value directly.");
    etr.Reset();
    while(etr.MoveNext()) 
     Console.WriteLine(etr.Key + ": " + 
                       etr.Value);
    
  }
}

listing 24
// Implement IEnumerable and IEnumerator.
using System;
using System.Collections;
 
class MyClass : IEnumerator, IEnumerable {
  char[] chrs = { 'A', 'B', 'C', 'D' };
  int idx = -1;
 
  // Implement IEnumerable.
  public IEnumerator GetEnumerator() {
    return this;
  }
 
  // The following methods implement IEnumerator.
 
  // Return the current object.
  public object Current {
    get {
      return chrs[idx];
    }
  }
 
  // Advance to the next object. 
  public bool MoveNext() {
    if(idx == chrs.Length-1) {
      Reset(); // reset enumerator at the end.
      return false;
    }
    
    idx++;
    return true;
  }
   
  // Reset the enumerator to the start.
  public void Reset() { idx = -1; } 
}
 
class EnumeratorImplDemo {
  public static void Main() {
    MyClass mc = new MyClass();
 
    // Display the contents of mc.
    foreach(char ch in mc)
      Console.Write(ch + " ");
 
    Console.WriteLine();
 
    // Display the contents of mc, again.
    foreach(char ch in mc)
      Console.Write(ch + " ");
 
    Console.WriteLine();
  }
}

listing 25
// A simple example of an iterator.
 
using System;
using System.Collections;
 
class MyClass {
  char[] chrs = { 'A', 'B', 'C', 'D' };
 
  // This iterator returns the characters
  // in the chrs array.
  public IEnumerator GetEnumerator() {
    foreach(char ch in chrs)
      yield return ch;
  }
}
 
class ItrDemo {
  public static void Main() {
    MyClass mc = new MyClass();
 
    foreach(char ch in mc)
      Console.Write(ch + " ");
 
    Console.WriteLine();
  }
}

listing 26
// Iterated values can be dynamically constructed.
 
using System;
using System.Collections;
 
class MyClass {
  char ch = 'A';
 
  // This iterator returns the letters
  // of the alphabet. 
  public IEnumerator GetEnumerator() {
    for(int i=0; i < 26; i++)
      yield return (char) (ch + i);
  }
}
 
class ItrDemo2 {
  public static void Main() {
    MyClass mc = new MyClass();
 
    foreach(char ch in mc)
      Console.Write(ch + " ");
 
    Console.WriteLine();
  }
}

listing 27
// Use yield break.
 
using System;
using System.Collections;
 
class MyClass {
  char ch = 'A';
 
  // This iterator returns the first 10
  // letters of the alphabet.
  public IEnumerator GetEnumerator() {
    for(int i=0; i < 26; i++) {
      if(i == 10) yield break; // stop iterator early
      yield return (char) (ch + i);
    }
  }
}
 
class ItrDemo3 {
  public static void Main() {
    MyClass mc = new MyClass();
 
    foreach(char ch in mc)
      Console.Write(ch + " ");
 
    Console.WriteLine();
  }
}

listing 28
// Multiple yield statements are allowed.
 
using System;
using System.Collections;
 
class MyClass {
  // This iterator returns the letters
  // A, B, C, D and E.
  public IEnumerator GetEnumerator() {
    yield return 'A';
    yield return 'B';
    yield return 'C';
    yield return 'D';
    yield return 'E';
  }
}
 
class ItrDemo5 {
  public static void Main() {
    MyClass mc = new MyClass();
 
    foreach(char ch in mc)
      Console.Write(ch + " ");
 
    Console.WriteLine();
  }
}

listing 29
// Use named iterators and the Enumerable pattern.
 
using System;
using System.Collections;
 
class MyClass {
  char ch = 'A';
 
  // This iterator returns the letters
  // of the alphabet, beginning at A and 
  // stopping at the specified starting point.
  public IEnumerable MyItr(int end) {
    for(int i=0; i < end; i++)
      yield return (char) (ch + i);
  }
 
  // This iterator returns the specified
  // range of letters
  public IEnumerable MyItr(int begin, int end) {
    for(int i=begin; i < end; i++)
      yield return (char) (ch + i);
  }
}
 
class ItrDemo4 {
  public static void Main() {
    MyClass mc = new MyClass();
 
    Console.WriteLine("Iterator the first 7 letters:");
    foreach(char ch in mc.MyItr(7))
      Console.Write(ch + " ");
 
    Console.WriteLine("\n");
 
 
    Console.WriteLine("Iterate letters from F to L:");
    foreach(char ch in mc.MyItr(5, 12))
      Console.Write(ch + " ");
 
    Console.WriteLine();
  }
}

listing 30
// A simple example of a generic iterator.
 
using System;
using System.Collections.Generic;
 
class MyClass<T> {
  T[] array;
 
  public MyClass(T[] a) {
    array = a;
  }
 
  // This iterator returns the characters
  // in the chrs array.
  public IEnumerator<T> GetEnumerator() {
    foreach(T obj in array)
      yield return obj;
  }
}
 
class GenericItrDemo {
  public static void Main() {
    int[] nums = { 4, 3, 6, 4, 7, 9 };
    MyClass<int> mc = new MyClass<int>(nums);
 
    foreach(int x in mc)
      Console.Write(x + " ");
 
    Console.WriteLine();
 
 
   bool[] bVals = { true, true, false, true };
    MyClass<bool> mc2 = new MyClass<bool>(bVals);
 
    foreach(bool b in mc2)
      Console.Write(b + " ");
 
    Console.WriteLine();
  }
}

listing 1
// Access the Internet.
 
using System;
using System.Net;
using System.IO;
 
class NetDemo { 
  public static void Main() {
    int ch;
 
    // First, create a WebRequest to a URI.
    HttpWebRequest req = (HttpWebRequest)
           WebRequest.Create("http://www.McGraw-Hill.com");
 
    // Next, send that request and return the response.
    HttpWebResponse resp = (HttpWebResponse)
           req.GetResponse();
 
    // From the response, obtain an input stream.
    Stream istrm = resp.GetResponseStream();
 
 
    /* Now, read and display the html present at
       the specified URI.  So you can see what is
       being displayed, the data is shown
       400 characters at a time.  After each 400
       characters are displayed, you must press
       ENTER to get the next 400. */
  
    for(int i=1; ; i++) {
      ch =  istrm.ReadByte();
      if(ch == -1) break;
      Console.Write((char) ch);
      if((i%400)==0) {
        Console.Write("\nPress Enter.");
        Console.ReadLine();
      }
    }
 
    // Close the Response. This also closes istrm.
    resp.Close();
  }
}

listing 2
// Handle network exceptions.
 
using System;
using System.Net;
using System.IO;
 
class NetExcDemo { 
  public static void Main() {
    int ch;
 
    try {
 
      // First, create a WebRequest to a URI.
      HttpWebRequest req = (HttpWebRequest)
             WebRequest.Create("http://www.McGraw-Hill.com");
 
      // Next, send that request and return the response.
      HttpWebResponse resp = (HttpWebResponse)
             req.GetResponse();
 
      // From the response, obtain an input stream.
      Stream istrm = resp.GetResponseStream();
 
      /* Now, read and display the html present at
         the specified URI.  So you can see what is
         being displayed, the data is shown
         400 characters at a time.  After each 400
         characters are displayed, you must press
         ENTER to get the next 400. */
  
      for(int i=1; ; i++) {
        ch =  istrm.ReadByte();
        if(ch == -1) break;
        Console.Write((char) ch);
        if((i%400)==0) {
          Console.Write("\nPress Enter.");
          Console.ReadLine();
        }
      }
 
      // Close the Response. This also closes istrm.
      resp.Close();
 
    } catch(WebException exc) {
      Console.WriteLine("Network Error: " + exc.Message + 
                        "\nStatus code: " + exc.Status);
    } catch(ProtocolViolationException exc) {
      Console.WriteLine("Protocol Error: " + exc.Message);
    } catch(UriFormatException exc) {
      Console.WriteLine("URI Format Error: " + exc.Message);
    } catch(NotSupportedException exc) {
      Console.WriteLine("Unknown Protocol: " + exc.Message);
    } catch(IOException exc) {
      Console.WriteLine("I/O Error: " + exc.Message);
    } catch(System.Security.SecurityException exc) {
      Console.WriteLine("Security Exception: " + exc.Message);
    } catch(InvalidOperationException exc) {
      Console.WriteLine("Invalid Operation: " + exc.Message);
    }
  }
}

listing 3
// Use Uri.
 
using System;
using System.Net;
 
class UriDemo { 
  public static void Main() {
 
    Uri sample = new Uri("http://MySite.com/somefile.txt?SomeQuery");
 
    Console.WriteLine("Host: " + sample.Host);
    Console.WriteLine("Port: " + sample.Port);
    Console.WriteLine("Scheme: " + sample.Scheme);
    Console.WriteLine("Local Path: " + sample.LocalPath);
    Console.WriteLine("Query: " + sample.Query);
    Console.WriteLine("Path and query: " + sample.PathAndQuery);
 
  }
}

listing 4
// Examine the headers.
 
using System;
using System.Net;
 
class HeaderDemo { 
  public static void Main() {
 
    // Create a WebRequest to a URI.
    HttpWebRequest req = (HttpWebRequest)
           WebRequest.Create("http://www.McGraw-Hill.com");
 
    // Send that request and return the response.
    HttpWebResponse resp = (HttpWebResponse)
           req.GetResponse();
 
    // Obtain a list of the names.
    string[] names = resp.Headers.AllKeys;
 
    // Display the header name/value pairs.
    Console.WriteLine("{0,-20}{1}\n", "Name", "Value");
    foreach(string n in names)
      Console.WriteLine("{0,-20}{1}", n, resp.Headers[n]);
 
    // Close the Response. 
    resp.Close();
  }
}

listing 5
/* Examine Cookies.
 
   To see what cookies a web site uses,
   specify its name on the command line.
   For example, if you call this program
   CookieDemo, then
 
     CookieDemo http://msn.com
 
   displays the cookies associated with msn.com.
*/
 
using System;
using System.Net;
 
class CookieDemo { 
  public static void Main(string[] args) {
 
    if(args.Length != 1) {
      Console.WriteLine("Usage: CookieDemo <uri>");
      return ;
    }
 
    // Create a WebRequest to the specified URI.
    HttpWebRequest req = (HttpWebRequest)
           WebRequest.Create(args[0]); 
 
    // Get an empty cookie container.
    req.CookieContainer = new CookieContainer();
 
    // Send the request and return the response.
    HttpWebResponse resp = (HttpWebResponse)
           req.GetResponse();
 
    // Display the cookies.
    Console.WriteLine("Number of cookies: " + 
                        resp.Cookies.Count);
    Console.WriteLine("{0,-20}{1}", "Name", "Value");
 
    for(int i=0; i < resp.Cookies.Count; i++)
      Console.WriteLine("{0, -20}{1}",
                         resp.Cookies[i].Name,
                         resp.Cookies[i].Value);
 
    // Close the Response. 
    resp.Close();
  }
}

listing 6
/* Use LastModified. 
 
   To see the date on which a web site was
   last modified, enter its URI on the command
   line. For example, if you call this program
   LastModified, then see the date of last
   modification for HerbSchildt.com enter
  
     LastModifiedDemo http://HerbSchildt.com 
*/ 
 
using System; 
using System.Net; 
 
class LastModifiedDemo {  
  public static void Main(string[] args) { 
 
    if(args.Length != 1) { 
      Console.WriteLine("Usage: LastModifiedDemo <uri>"); 
      return ; 
    } 
 
    HttpWebRequest req = (HttpWebRequest) 
           WebRequest.Create(args[0]); 
 
    HttpWebResponse resp = (HttpWebResponse) 
           req.GetResponse(); 
 
    Console.WriteLine("Last modified: " + resp.LastModified); 
 
    resp.Close(); 
  } 
}

listing 7
/* MiniCrawler: A skeletal Web crawler.
 
   Usage:
     To start crawling, specify a starting
     URI on the command line. For example,
     to start at McGraw-Hill.com use this
     command line:
  
       MiniCrawler http://McGraw-Hill.com 
  
*/ 
 
using System;
using System.Net;
using System.IO;
 
class MiniCrawler { 
 
  // Find a link in a content string.
  static string FindLink(string htmlstr, 
                         ref int startloc) {
    int i;
    int start, end;
    string uri = null;
    string lowcasestr = htmlstr.ToLower();
 
    i = lowcasestr.IndexOf("href=\"http", startloc);
    if(i != -1) {
      start = htmlstr.IndexOf('"', i) + 1;
      end = htmlstr.IndexOf('"', start);
      uri = htmlstr.Substring(start, end-start);
      startloc = end;
    }
            
    return uri;
  }
 
  public static void Main(string[] args) {
    string link = null;
    string str;
    string answer;
 
    int curloc; // holds current location in response
 
    if(args.Length != 1) {
      Console.WriteLine("Usage: MiniCrawler <uri>");
      return ;
    }
 
    string uristr = args[0]; // holds current URI
 
    try {
 
      do {
        Console.WriteLine("Linking to " + uristr);
 
        // Create a WebRequest to the specified URI.
        HttpWebRequest req = (HttpWebRequest)
               WebRequest.Create(uristr);
 
        uristr = null; // disallow further use of this URI
 
        // Send that request and return the response.
        HttpWebResponse resp = (HttpWebResponse)
               req.GetResponse();
 
        // From the response, obtain an input stream.
        Stream istrm = resp.GetResponseStream();
 
        // Wrap the input stream in a StreamReader.
        StreamReader rdr = new StreamReader(istrm);
 
        // Read in the entire page.
        str = rdr.ReadToEnd();
 
        curloc = 0;
       
        do {
          // Find the next URI to link to.
          link = FindLink(str, ref curloc);
 
          if(link != null) {
            Console.WriteLine("Link found: " + link);
 
            Console.Write("Link, More, Quit?");
            answer = Console.ReadLine();
 
            if(string.Compare(answer, "L", true) == 0) {
              uristr = string.Copy(link);
              break;
            } else if(string.Compare(answer, "Q", true) == 0) {
              break;
            } else if(string.Compare(answer, "M", true) == 0) {
              Console.WriteLine("Searching for another link.");
            }
          } else {
            Console.WriteLine("No link found.");
            break;
          }
 
        } while(link.Length > 0);
 
        // Close the Response.
        resp.Close();
      } while(uristr != null);
 
    } catch(WebException exc) {
      Console.WriteLine("Network Error: " + exc.Message + 
                        "\nStatus code: " + exc.Status);
    } catch(ProtocolViolationException exc) {
      Console.WriteLine("Protocol Error: " + exc.Message);
    } catch(UriFormatException exc) {
      Console.WriteLine("URI Format Error: " + exc.Message);
    } catch(NotSupportedException exc) {
      Console.WriteLine("Unknown Protocol: " + exc.Message);
    } catch(IOException exc) {
      Console.WriteLine("I/O Error: " + exc.Message);
    }
 
    Console.WriteLine("Terminating MiniCrawler.");
  }
}

listing 8
// Use WebClient to download information into a file.
 
using System;
using System.Net;
using System.IO;
 
class WebClientDemo { 
  public static void Main() {
    WebClient user = new WebClient();
    string uri = "http://www.McGraw-Hill.com";
    string fname = "data.txt";
    
    try {
      Console.WriteLine("Downloading data from " +
                        uri + " to " + fname);
      user.DownloadFile(uri, fname);
    } catch (WebException exc) {
      Console.WriteLine(exc);
    }
 
    Console.WriteLine("Download complete.");
  }
}

listing 1
// A simple Cipher component.  Call this file CipherLib.cs.
 
using System.ComponentModel;
 
namespace CipherLib { // put component in its own namespace
 
  // Notice that CipherComp inherits Component.
  public class CipherComp : Component { 
 
    // Encode a string.
    public string Encode(string msg) {
      string temp = "";
 
      for(int i=0; i < msg.Length; i++)
        temp += (char) (msg[i] + 1);
 
      return temp;
    }
 
    // Decode a string.
    public string Decode(string msg) {
      string temp = "";
 
      for(int i=0; i < msg.Length; i++)
        temp += (char) (msg[i] - 1);
 
 
      return temp;
    }
  }
}

listing 2
// A client that uses CipherComp.
 
using System;
using CipherLib; // import CipherComp's namespace
 
class CipherCompClient {
  public static void Main() {
    CipherComp cc = new CipherComp();
 
    string text = "This is a test";
 
    string ciphertext = cc.Encode(text);
    Console.WriteLine(ciphertext);
 
    string plaintext = cc.Decode(ciphertext);
    Console.WriteLine(plaintext);
 
    cc.Dispose(); // free resources
  }
}

listing 3
// A skeletal implementation of a component that uses Dispose(bool).
class MyComp : Component {
  bool isDisposed; // true if component is disposed
 
  public MyComp {
    isDispose = false;
    // ...
  }
 
  ~MyComp() {
    Dispose(false);
  }
 
  protected override void Dispose(bool dispAll) {
    if(!isDisposed) {
      if(dispAll) {
        // release managed resources here
        isDisposed = true; // set component to disposed
      }
      // release unmanaged resources here
      base.Dispose(dispAll);
    }
  }
}

listing 4
// An enhanced cipher component that maintains a log file. 
 
using System; 
using System.ComponentModel; 
using System.IO; 
 
namespace CipherLib { 
 
  // An Cipher component that maintains a log file.
  public class CipherComp : Component {  
    static int useID = 0;
    int id; // instance id
    bool isDisposed; // true if component is disposed. 
    FileStream log;
 
    // Constructor 
    public CipherComp() { 
      isDisposed = false; // component not disposed 
      try { 
        log = new FileStream("CipherLog" + useID, FileMode.Create); 
        id = useID;
        useID++;
      } catch (FileNotFoundException exc) { 
        Console.WriteLine(exc); 
        log = null;
      } 
    } 
 
    // Destructor 
    ~CipherComp() { 
       Console.WriteLine("Destructor for component "
                         + id);
       Dispose(false); 
    } 
 
    // Encode the file. Return and store result.
    public string Encode(string msg) { 
 
      string temp = ""; 
 
      for(int i=0;i < msg.Length; i++)  
        temp += (char) (msg[i] + 1);         
 
      // Store in log file. 
      for(int i=0; i < temp.Length; i++) 
        log.WriteByte((byte) temp[i]); 
 
      return temp;
    } 
 
    // Decode the message. Return and store result. 
    public string Decode(string msg) { 
 
      string temp = ""; 
 
      for(int i=0; i < msg.Length; i++) 
        temp += (char) (msg[i] - 1); 
 
      // Store in log file. 
      for(int i=0; i < temp.Length; i++) 
        log.WriteByte((byte) temp[i]); 
 
      return temp;
    } 
 
    protected override void Dispose(bool dispAll) { 
      Console.WriteLine("Dispose(" + dispAll +
                        ") for component " + id);
 
      if(!isDisposed) { 
        if(dispAll) { 
          Console.WriteLine("Closing file for " +
                            "component " + id);
          log.Close(); // close encoded file 
          isDisposed = true; 
        } 
        // no unmanaged resources to release 
        base.Dispose(dispAll); 
      } 
    } 
  } 
}

listing 5
// Another client that uses CipherComp. 
 
using System; 
using CipherLib; // import CipherComp's namespace 
 
class CipherCompClient { 
  public static void Main() { 
    CipherComp cc = new CipherComp(); 
 
    string text = "Testing"; 
 
    string ciphertext = cc.Encode(text); 
    Console.WriteLine(ciphertext); 
 
    string plaintext = cc.Decode(ciphertext); 
    Console.WriteLine(plaintext); 
 
    text = "Components are powerful.";
 
    ciphertext = cc.Encode(text); 
    Console.WriteLine(ciphertext); 
 
    plaintext = cc.Decode(ciphertext); 
    Console.WriteLine(plaintext); 
 
    cc.Dispose(); // free resources 
  } 
}

listing 6
// Encode the file. Return and store result.
public string Encode(string msg) { 
 
  // Prevent use of a disposed component.
  if(isDisposed) {
    Console.WriteLine("Error: Component disposed.");
    return null;
  }
 
  string temp = ""; 
 
  for(int i=0;i < msg.Length; i++)  
    temp += (char) (msg[i] + 1);         
 
  // Store in log file. 
  for(int i=0; i < temp.Length; i++) 
    log.WriteByte((byte) temp[i]); 
 
  return temp;

 
// Decode the message. Return and store result. 
public string Decode(string msg) { 
 
  // Prevent use of a disposed component.
  if(isDisposed) {
    Console.WriteLine("Error: Component disposed.");
    return null;
  }
 
  string temp = ""; 
 
  for(int i=0; i < msg.Length; i++) 
    temp += (char) (msg[i] - 1); 
 
  // Store in log file. 
  for(int i=0; i < temp.Length; i++) 
    log.WriteByte((byte) temp[i]); 
 
  return temp;
}

listing 7
// Employ the using statement.
 
using System; 
using CipherLib; // import CipherComp's namespace 
 
class CipherCompClient { 
  public static void Main() { 
 
    // cc will be disposed when this block ends.
    using(CipherComp cc = new CipherComp()) {
 
      string text = "The using statement."; 
 
      string ciphertext = cc.Encode(text); 
      Console.WriteLine(ciphertext); 
 
      string plaintext = cc.Decode(ciphertext); 
      Console.WriteLine(plaintext); 
    }
 
  } 
}

listing 8
// Demonstrate a component container. 
 
using System; 
using System.ComponentModel; 
using CipherLib; // import CipherComp's namespace 
 
class UseContainer { 
  public static void Main(string[] args) { 
    string str = "Using containers.";
    Container cont = new Container(); 
    
    CipherComp cc = new CipherComp(); 
    CipherComp cc2 = new CipherComp(); 
 
    cont.Add(cc); 
    cont.Add(cc2, "Second Component"); 
 
    Console.WriteLine("First message: " +  str); 
    str = cc.Encode(str); 
    Console.WriteLine("First message encoded: " + 
                      str); 
 
    str = cc.Decode(str); 
    Console.WriteLine("First message decoded: " + 
                      str); 
 
    str = "one, two, three"; 
    Console.WriteLine("Second message: " +  str); 
 
    str = cc2.Encode(str); 
    Console.WriteLine("Second message encoded: " + 
                      str); 
 
    str = cc2.Decode(str); 
    Console.WriteLine("Second message decoded: " + 
                      str); 
 
    Console.WriteLine("\ncc2's name: " + cc2.Site.Name); 
 
    Console.WriteLine();
 
    // Release both components. 
    cont.Dispose(); 
  } 
}

listing 1
// A form-based Windows Skeleton.
 
using System;
using System.Windows.Forms;
 
// WinSkel is derived from Form.
class WinSkel : Form {
 
  public WinSkel() {
    // Give the window a name.
    Text = "A Windows Skeleton";
  }  
 
  // Main is used only to start the application.
  [STAThread]
  public static void Main() {
    WinSkel skel = new WinSkel(); // create a form
 
    // Start the window running.
    Application.Run(skel);
  }
}

listing 2
// Add a Button.
 
using System;
using System.Windows.Forms;
using System.Drawing;
 
class ButtonForm : Form {
  Button MyButton = new Button();
 
  public ButtonForm() {
    Text = "Using a Button";
 
    MyButton = new Button();
    MyButton.Text = "Press Here";
    MyButton.Location = new Point(100, 200);
 
    Controls.Add(MyButton);
  }  
 
  [STAThread]
  public static void Main() {
    ButtonForm skel = new ButtonForm();
 
    Application.Run(skel);
  }
}

listing 3
// Handle button messages.
 
using System;
using System.Windows.Forms;
using System.Drawing;
 
class ButtonForm : Form {
  Button MyButton = new Button();
 
  public ButtonForm() {
    Text = "Respond to a Button";
 
    MyButton = new Button();
    MyButton.Text = "Press Here";
    MyButton.Location = new Point(100, 200);
 
    // Add button event handler to list.
    MyButton.Click += MyButtonClick;
 
    Controls.Add(MyButton);
  }  
 
  [STAThread]
  public static void Main() {
    ButtonForm skel = new ButtonForm();
 
    Application.Run(skel);
  }
 
  // Handler for MyButton.
  protected void MyButtonClick(object who, EventArgs e) {
 
    if(MyButton.Top == 200)
      MyButton.Location = new Point(10, 10);
    else
      MyButton.Location = new Point(100, 200);
  }
}

listing 4
// An Alternative button handler.
protected void MyButtonClick(object who, EventArgs e) { 
  Button b = (Button) who; 
 
  if(b.Top == 200) 
    b.Location = new Point(10, 10); 
  else 
    b.Location = new Point(100, 200); 
}

listing 5
// Add a stop button.
 
using System;
using System.Windows.Forms;
using System.Drawing;
 
class ButtonForm : Form {
  Button MyButton;
  Button StopButton;
 
  public ButtonForm() {
    Text = "Adding a Stop Button";
 
    // Create the buttons.
    MyButton = new Button();
    MyButton.Text = "Press Here";
    MyButton.Location = new Point(100, 200);
 
    StopButton = new Button();
    StopButton.Text = "Stop";
    StopButton.Location = new Point(100, 100);
 
    // Add the button event handlers to the window.
    MyButton.Click += MyButtonClick;
    Controls.Add(MyButton);
    StopButton.Click += StopButtonClick;
    Controls.Add(StopButton);
  }  
 
  [STAThread]
  public static void Main() {
    ButtonForm skel = new ButtonForm();
 
    Application.Run(skel);
  }
 
  // Handler for MyButton.
  protected void MyButtonClick(object who, EventArgs e) {
 
    if(MyButton.Top == 200)
      MyButton.Location = new Point(10, 10);
    else
      MyButton.Location = new Point(100, 200);
  }
 
  // Handler for StopButton.
  protected void StopButtonClick(object who, EventArgs e) {
 
    // If users answers Yes, terminate the program.
    DialogResult result = MessageBox.Show("Stop Program?",
                            "Terminate",
                            MessageBoxButtons.YesNo);
 
    if(result == DialogResult.Yes) Application.Exit();
  }
}

listing 6
// Add a Main Menu.
 
using System;
using System.Windows.Forms;
 
class MenuForm : Form {
  MainMenu MyMenu;
 
  public MenuForm() {
    Text = "Adding a Main Menu";
 
    // Create a main menu object.
    MyMenu  = new MainMenu();
 
    // Add top-level menu items to the menu.
    MenuItem m1 = new MenuItem("File");
    MyMenu.MenuItems.Add(m1);
 
    MenuItem m2 = new MenuItem("Tools");
    MyMenu.MenuItems.Add(m2);
 
    // Create File submenu
    MenuItem subm1 = new MenuItem("Open");
    m1.MenuItems.Add(subm1);
 
    MenuItem subm2 = new MenuItem("Close");
    m1.MenuItems.Add(subm2);
 
    MenuItem subm3 = new MenuItem("Exit");
    m1.MenuItems.Add(subm3);
 
    // Create Tools submenu
    MenuItem subm4 = new MenuItem("Coordinates");
    m2.MenuItems.Add(subm4);
 
    MenuItem subm5 = new MenuItem("Change Size");
    m2.MenuItems.Add(subm5);
 
    MenuItem subm6 = new MenuItem("Restore");
    m2.MenuItems.Add(subm6);
 
 
    // Add event handlers for the menu items.
    subm1.Click += MMOpenClick;
    subm2.Click += MMCloseClick;
    subm3.Click += MMExitClick;
    subm4.Click += MMCoordClick;
    subm5.Click += MMChangeClick;
    subm6.Click += MMRestoreClick;
 
    // Assign the menu to the form.
    Menu = MyMenu;
  }  
 
  [STAThread]
  public static void Main() {
    MenuForm skel = new MenuForm();
 
    Application.Run(skel);
  }
 
  // Handler for main menu Coordinates selection.
  protected void MMCoordClick(object who, EventArgs e) {
    // Create a string that contains the coordinates.
    string size =
      String.Format("{0}: {1}, {2}\n{3}: {4}, {5} ",
                    "Top, Left", Top, Left,
                    "Bottom, Right", Bottom, Right);
 
    // Display a message box.
    MessageBox.Show(size, "Window Coordinates",
                    MessageBoxButtons.OK);
  }
 
  // Handler for main menu Change selection.
  protected void MMChangeClick(object who, EventArgs e) {
    Width = Height = 200;
  }
 
  // Handler for main menu Restore selection.
  protected void MMRestoreClick(object who, EventArgs e) {
    Width = Height = 300;
  }
 
  // Handler for main menu Open selection.
  protected void MMOpenClick(object who, EventArgs e) {
 
    MessageBox.Show("Inactive", "Inactive",
                    MessageBoxButtons.OK);
  }
 
  // Handler for main menu Open selection.
  protected void MMCloseClick(object who, EventArgs e) {
 
    MessageBox.Show("Inactive", "Inactive",
                    MessageBoxButtons.OK);
  }
 
  // Handler for main menu Exit selection.
  protected void MMExitClick(object who, EventArgs e) {
 
    DialogResult result = MessageBox.Show("Stop Program?",
                            "Terminate",
                             MessageBoxButtons.YesNo);
 
    if(result == DialogResult.Yes) Application.Exit();
  }
}

listing 7
// Use a MenuStrip.
 
using System; 
using System.Windows.Forms; 
 
class MenuForm : Form { 
  MenuStrip MyMenu; // use a MenuStrip 
 
  public MenuForm() { 
    Text = "Use a MenuStrip"; 
 
    // Create a main menu object. 
    MyMenu  = new MenuStrip(); 
 
    // Add top-level menu items to the menu. 
    ToolStripMenuItem m1 = new ToolStripMenuItem("File"); 
    MyMenu.Items.Add(m1); 
 
    ToolStripMenuItem m2 = new ToolStripMenuItem("Tools"); 
    MyMenu.Items.Add(m2); 
 
    // Create File submenu 
    ToolStripMenuItem subm1 = new ToolStripMenuItem("Open"); 
    m1.DropDownItems.Add(subm1); 
 
    ToolStripMenuItem subm2 = new ToolStripMenuItem("Close"); 
    m1.DropDownItems.Add(subm2); 
 
    ToolStripMenuItem subm3 = new ToolStripMenuItem("Exit"); 
    m1.DropDownItems.Add(subm3); 
 
    // Create Tools submenu 
    ToolStripMenuItem subm4 = new ToolStripMenuItem("Coordinates"); 
    m2.DropDownItems.Add(subm4); 
 
    ToolStripMenuItem subm5 = new ToolStripMenuItem("Change Size"); 
    m2.DropDownItems.Add(subm5); 
 
    ToolStripMenuItem subm6 = new ToolStripMenuItem("Restore");
    m2.DropDownItems.Add(subm6); 
 
 
    // Add event handlers for the menu items. 
    subm1.Click += MMOpenClick; 
    subm2.Click += MMCloseClick; 
    subm3.Click += MMExitClick; 
    subm4.Click += MMCoordClick; 
    subm5.Click += MMChangeClick; 
    subm6.Click += MMRestoreClick; 
 
    // Add to list of controls.
    Controls.Add(MyMenu);
 
    // Assign the menu to the form. 
    MainMenuStrip = MyMenu; 
  }   
 
  [STAThread] 
  public static void Main() { 
    MenuForm skel = new MenuForm(); 
 
    // Enable visual styles for Windows XP.
    Application.EnableVisualStyles(); 
 
    Application.Run(skel); 
  } 
 
  // Handler for main menu Coordinates selection. 
  protected void MMCoordClick(object who, EventArgs e) { 
    // Create a string that contains the coordinates. 
    string size = 
      String.Format("{0}: {1}, {2}\n{3}: {4}, {5} ", 
                    "Top, Left", Top, Left, 
                    "Bottom, Right", Bottom, Right); 
 
    // Display a message box. 
    MessageBox.Show(size, "Window Coordinates", 
                    MessageBoxButtons.OK); 
  } 
 
  // Handler for main menu Change selection. 
  protected void MMChangeClick(object who, EventArgs e) { 
    Width = Height = 200; 
  } 
 
  // Handler for main menu Restore selection. 
  protected void MMRestoreClick(object who, EventArgs e) { 
    Width = Height = 300; 
  } 
 
  // Handler for main menu Open selection. 
  protected void MMOpenClick(object who, EventArgs e) { 
 
    MessageBox.Show("Inactive", "Inactive", 
                    MessageBoxButtons.OK); 
  } 
 
  // Handler for main menu Open selection. 
  protected void MMCloseClick(object who, EventArgs e) { 
 
    MessageBox.Show("Inactive", "Inactive", 
                    MessageBoxButtons.OK); 
  } 
 
  // Handler for main menu Exit selection. 
  protected void MMExitClick(object who, EventArgs e) { 
 
    DialogResult result = MessageBox.Show("Stop Program?", 
                            "Terminate", 
                             MessageBoxButtons.YesNo); 
 
    if(result == DialogResult.Yes) Application.Exit(); 
  } 
}

listing 1
/* 
   This module contains the recursive descent
   parser that does not use variables.
*/
 
using System;
 
// Exception class for parser errors.
class ParserException : ApplicationException {
  public ParserException(string str) : base(str) { } 
 
  public override string ToString() {
    return Message;
  }
}
 
class Parser {
  // Enumerate token types.
  enum Types { NONE, DELIMITER, VARIABLE, NUMBER };
  // Enumerate error types.
  enum Errors { SYNTAX, UNBALPARENS, NOEXP, DIVBYZERO };
 
  string exp;    // refers to expression string
  int expIdx;    // current index into the expression
  string token;  // holds current token
  Types tokType; // holds token's type
 
  // Parser entry point.
  public double Evaluate(string expstr)
  {
    double result;
  
    exp = expstr;
    expIdx = 0; 
 
    try { 
      GetToken();
      if(token == "") {
        SyntaxErr(Errors.NOEXP); // no expression present
        return 0.0;
      }
 
      EvalExp2(out result);
 
      if(token != "") // last token must be null
        SyntaxErr(Errors.SYNTAX);
 
      return result;
    } catch (ParserException exc) {
      // Add other error handling here, as desired.
      Console.WriteLine(exc);
      return 0.0;
    }
  }
  
  // Add or subtract two terms.
  void EvalExp2(out double result)
  {
    string op;
    double partialResult;
  
    EvalExp3(out result);
    while((op = token) == "+" || op == "-") {
      GetToken();
      EvalExp3(out partialResult);
      switch(op) {
        case "-":
          result = result - partialResult;
          break;
        case "+":
          result = result + partialResult;
          break;
      }
    }
  }
  
  // Multiply or divide two factors.
  void EvalExp3(out double result)
  {
    string op;
    double partialResult = 0.0;
  
    EvalExp4(out result);
    while((op = token) == "*" ||
           op == "/" || op == "%") {
      GetToken();
      EvalExp4(out partialResult);
      switch(op) {
        case "*":
          result = result * partialResult;
          break;
        case "/":
          if(partialResult == 0.0)
            SyntaxErr(Errors.DIVBYZERO);
          result = result / partialResult;
          break;
        case "%":
          if(partialResult == 0.0)
            SyntaxErr(Errors.DIVBYZERO);
          result = (int) result % (int) partialResult;
          break;
      }
    }
  }
  
  // Process an exponent.
  void EvalExp4(out double result)
  {
    double partialResult, ex;
    int t;
  
    EvalExp5(out result);
    if(token == "^") {
      GetToken();
      EvalExp4(out partialResult);
      ex = result;
      if(partialResult == 0.0) {
        result = 1.0;
        return;
      }
      for(t=(int)partialResult-1; t > 0; t--)
        result = result * (double)ex;
    }
  }
  
  // Evaluate a unary + or -.
  void EvalExp5(out double result)
  {
    string  op;
  
    op = "";
    if((tokType == Types.DELIMITER) &&
        token == "+" || token == "-") {
      op = token;
      GetToken();
    }
    EvalExp6(out result);
    if(op == "-") result = -result;
  }
  
  // Process a parenthesized expression.
  void EvalExp6(out double result)
  {
    if((token == "(")) {
      GetToken();
      EvalExp2(out result);
      if(token != ")")
        SyntaxErr(Errors.UNBALPARENS);
      GetToken();
    }
    else Atom(out result);
  }
  
  // Get the value of a number.
  void Atom(out double result)
  {
    switch(tokType) {
      case Types.NUMBER:
        try {
          result = Double.Parse(token);
        } catch (FormatException) {
          result = 0.0;
          SyntaxErr(Errors.SYNTAX);
        }
        GetToken();
        return;
      default:
        result = 0.0;
        SyntaxErr(Errors.SYNTAX);
        break;
    }
  }
  
  // Handle a syntax error.
  void SyntaxErr(Errors error)
  {
    string[] err = {
      "Syntax Error",
      "Unbalanced Parentheses",
      "No Expression Present",
      "Division by Zero"
    };
 
    throw new ParserException(err[(int)error]);
  }
  
  // Obtain the next token.
  void GetToken()
  {
    tokType = Types.NONE;
    token = "";
   
    if(expIdx == exp.Length) return; // at end of expression
  
    // skip over white space
    while(expIdx < exp.Length &&
          Char.IsWhiteSpace(exp[expIdx])) ++expIdx;
 
    // trailing whitespace ends expression
    if(expIdx == exp.Length) return;
 
    if(IsDelim(exp[expIdx])) { // is operator
      token += exp[expIdx];
      expIdx++;
      tokType = Types.DELIMITER;
    }
    else if(Char.IsLetter(exp[expIdx])) { // is variable
      while(!IsDelim(exp[expIdx])) {
        token += exp[expIdx];
        expIdx++;
        if(expIdx >= exp.Length) break;
      }
      tokType = Types.VARIABLE;
    }
    else if(Char.IsDigit(exp[expIdx])) { // is number
      while(!IsDelim(exp[expIdx])) {
        token += exp[expIdx];
        expIdx++;
        if(expIdx >= exp.Length) break;
      }
      tokType = Types.NUMBER;
    }
  }
  
  // Return true if c is a delimiter.
  bool IsDelim(char c)
  {
    if((" +-/*%^=()".IndexOf(c) != -1))
      return true;
    return false;
  }
  
}

listing 2
// Demonstrate the parser.
 
using System;
 
class ParserDemo {
  public static void Main()
  {
    string expr;
    Parser p = new Parser();
 
    Console.WriteLine("Enter an empty expression to stop.");
 
    for(;;) {
      Console.Write("Enter expression: ");
      expr = Console.ReadLine();
      if(expr == "") break;
      Console.WriteLine("Result: " + p.Evaluate(expr));
    }
  }
}

listing 3
/* 
   This module contains the recursive descent
   parser that recognizes variables.
*/
 
using System;
 
// Exception class for parser errors.
class ParserException : ApplicationException {
  public ParserException(string str) : base(str) { } 
 
  public override string ToString() {
    return Message;
  }
}
 
class Parser {
  // Enumerate token types.
  enum Types { NONE, DELIMITER, VARIABLE, NUMBER };
  // Enumerate error types.
  enum Errors { SYNTAX, UNBALPARENS, NOEXP, DIVBYZERO };
 
  string exp;    // refers to expression string
  int expIdx;    // current index into the expression
  string token;  // holds current token
  Types tokType; // holds token's type
 
  // Array for variables.
  double[] vars = new double[26];
 
  public Parser() {
    // Initialize the variables to zero.
    for(int i=0; i < vars.Length; i++) 
       vars[i] = 0.0;
  }
 
  // Parser entry point.
  public double Evaluate(string expstr)
  {
    double result;
  
    exp = expstr;
    expIdx = 0; 
 
    try { 
      GetToken();
      if(token == "") {
        SyntaxErr(Errors.NOEXP); // no expression present
        return 0.0;
      }
 
      EvalExp1(out result); // now, call EvalExp1() to start
 
      if(token != "") // last token must be null
        SyntaxErr(Errors.SYNTAX);
 
      return result;
    } catch (ParserException exc) {
      // Add other error handling here, as desired.
      Console.WriteLine(exc);
      return 0.0;
    }
  }
  
  // Process an assignment.
  void EvalExp1(out double result)
  {
    int varIdx;
    Types ttokType;
    string temptoken;
 
    if(tokType == Types.VARIABLE) {
      // save old token
      temptoken = String.Copy(token);
      ttokType = tokType;
 
      // Compute the index of the variable.
      varIdx = Char.ToUpper(token[0]) - 'A';
 
      GetToken();
      if(token != "=") {
        PutBack(); // return current token
        // restore old token -- not an assignment
        token = String.Copy(temptoken);
        tokType = ttokType;
      }
      else {
        GetToken(); // get next part of exp
        EvalExp2(out result);
        vars[varIdx] = result;
        return;
      }
    }
 
    EvalExp2(out result);
  }
 
  // Add or subtract two terms.
  void EvalExp2(out double result)
  {
    string op;
    double partialResult;
  
    EvalExp3(out result);
    while((op = token) == "+" || op == "-") {
      GetToken();
      EvalExp3(out partialResult);
      switch(op) {
        case "-":
          result = result - partialResult;
          break;
        case "+":
          result = result + partialResult;
          break;
      }
    }
  }
  
  // Multiply or divide two factors.
  void EvalExp3(out double result)
  {
    string op;
    double partialResult = 0.0;
  
    EvalExp4(out result);
    while((op = token) == "*" ||
           op == "/" || op == "%") {
      GetToken();
      EvalExp4(out partialResult);
      switch(op) {
        case "*":
          result = result * partialResult;
          break;
        case "/":
          if(partialResult == 0.0)
            SyntaxErr(Errors.DIVBYZERO);
          result = result / partialResult;
          break;
        case "%":
          if(partialResult == 0.0)
            SyntaxErr(Errors.DIVBYZERO);
          result = (int) result % (int) partialResult;
          break;
      }
    }
  }
  
  // Process an exponent.
  void EvalExp4(out double result)
  {
    double partialResult, ex;
    int t;
  
    EvalExp5(out result);
    if(token == "^") {
      GetToken();
      EvalExp4(out partialResult);
      ex = result;
      if(partialResult == 0.0) {
        result = 1.0;
        return;
      }
      for(t=(int)partialResult-1; t > 0; t--)
        result = result * (double)ex;
    }
  }
  
  // Evaluate a unary + or -.
  void EvalExp5(out double result)
  {
    string  op;
  
    op = "";
    if((tokType == Types.DELIMITER) &&
        token == "+" || token == "-") {
      op = token;
      GetToken();
    }
    EvalExp6(out result);
    if(op == "-") result = -result;
  }
  
  // Process a parenthesized expression.
  void EvalExp6(out double result)
  {
    if((token == "(")) {
      GetToken();
      EvalExp2(out result);
      if(token != ")")
        SyntaxErr(Errors.UNBALPARENS);
      GetToken();
    }
    else Atom(out result);
  }
  
  // Get the value of a number or variable.
  void Atom(out double result)
  {
    switch(tokType) {
      case Types.NUMBER:
        try {
          result = Double.Parse(token);
        } catch (FormatException) {
          result = 0.0;
          SyntaxErr(Errors.SYNTAX);
        }
        GetToken();
        return;
      case Types.VARIABLE:
        result = FindVar(token);
        GetToken();
        return;
      default:
        result = 0.0;
        SyntaxErr(Errors.SYNTAX);
        break;
    }
  }
  
   // Return the value of a variable.
  double FindVar(string vname)
  {
    if(!Char.IsLetter(vname[0])){
      SyntaxErr(Errors.SYNTAX);
      return 0.0;
    }
    return vars[Char.ToUpper(vname[0])-'A'];
  }
 
  // Return a token to the input stream.
  void PutBack()  
  {
    for(int i=0; i < token.Length; i++) expIdx--;
  }
 
  // Handle a syntax error.
  void SyntaxErr(Errors error)
  {
    string[] err = {
      "Syntax Error",
      "Unbalanced Parentheses",
      "No Expression Present",
      "Division by Zero"
    };
 
    throw new ParserException(err[(int)error]);
  }
  
  // Obtain the next token.
  void GetToken()
  {
    tokType = Types.NONE;
    token = "";
   
    if(expIdx == exp.Length) return; // at end of expression
  
    // skip over white space
    while(expIdx < exp.Length &&
          Char.IsWhiteSpace(exp[expIdx])) ++expIdx;
 
    // trailing whitespace ends expression
    if(expIdx == exp.Length) return;
 
    if(IsDelim(exp[expIdx])) { // is operator
      token += exp[expIdx];
      expIdx++;
      tokType = Types.DELIMITER;
    }
    else if(Char.IsLetter(exp[expIdx])) { // is variable
      while(!IsDelim(exp[expIdx])) {
        token += exp[expIdx];
        expIdx++;
        if(expIdx >= exp.Length) break;
      }
      tokType = Types.VARIABLE;
    }
    else if(Char.IsDigit(exp[expIdx])) { // is number
      while(!IsDelim(exp[expIdx])) {
        token += exp[expIdx];
        expIdx++;
        if(expIdx >= exp.Length) break;
      }
      tokType = Types.NUMBER;
    }
  }
  
  // Return true if c is a delimiter.
  bool IsDelim(char c)
  {
    if((" +-/*%^=()".IndexOf(c) != -1))
      return true;
    return false;
  }  
}

 

  • 0
    点赞
  • 0
    收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值