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;
}
}