уторак, 8. мај 2012.

Examples for C# Essentials


Examples for C# Essentials

http://oreilly.com/catalog/csharpess/examples/

Introduction

A Minimal C# Program


class Test {
   static void Main() {
      System.Console.WriteLine("Welcome to C#!");
   }
}

C# Language Reference

Identifiers


Ko|n
@Ko|n

Types

Example: Building and Using Types

// Imports types from System namespace, such as Console
using System;
class Counter { // New types are typically classes or structs
  // --- Data members ---
  int value; // field of type int
  int scaleFactor; // field of type int

  // Constructor, used to initialize a type instance
  public Counter(int scaleFactor) { 
    this.scaleFactor = scaleFactor;  
  }
  // Method
  public void Inc() {
    value+=scaleFactor;
  }
  // Property
  public int Count {
    get {return value; }
  }
}
class Test {
  // Execution begins here
  static void Main() {

    // Create an instance of counter type
    Counter c = new Counter(5);
    c.Inc();
    c.Inc();
    Console.WriteLine(c.Count); // prints "10";

    // create another instance of counter type
    Counter d = new Counter(7);
    d.Inc();
    Console.WriteLine(d.Count); // prints "7";
   }
}
Implicit and Explicit Conversions

int x = 123456; // int is a 4-byte integer
long y = x; // implicit conversion to 8-byte integer
short z =(short)x // explicit conversion to 2-byte integer
Predefined Types

int i = 5;
System.Int32 i = 5;
Integral Types

int x = 5;
ulong y = 0x1234AF; // prefix with 0x for hexadecimal

int x = 123456;
long y = x; // implicit, no information lost
short z = (short)x; // explicit, truncates x
Floating Point Types

float x = 9.81f;
double y = 7E-02; // 0.07

int strength = 2;
int offset = 3;
float x = 9.53f * strength - offset;

float x = 3.53f;
int offset = (int)x;
Decimal Type

decimal x = 80603.454327m; // holds exact value
Char Type

'A' // simple character
'\u0041' // Unicode
'\x0041' // unsigned short hexadecimal
'\n' // escape sequence character
String Type

string a = "Heat";

string a1 = "\\\\server\\fileshare\\helloworld.cs";
string a2 = @"\\server\fileshare\helloworld.cs";
Console.WriteLine(a1==a2); // Prints "True"

string b1 = "First Line\r\nSecond Line";
string b2 = @"First Line
Second Line";
Console.WriteLine(b1==b2); // Prints "True"
Types and Memory
Simple Types Are Value Types

int i = 3;
string s = i.ToString();

// This is an explanatory version of System.Int32
namespace System {
  struct Int32 {
    ...
    public string ToString() {
      return ...;
    }
  }
}
// This is valid code, but we recommend you use the int alias
System.Int32 i = 5;
Value Types and Reference Types Side By Side

// Reference-type declaration
class PointR {
  public int x, y;
}
// Value-type declaration
struct PointV {
  public int x, y;
}
class Test {
  static void Main() {
    PointR a; // Local reference-type variable, uses 4 bytes of
              // memory on the stack to hold address
    PointV b; // Local value-type variable, uses 8 bytes of
              // memory on the stack for x and y
    a = new PointR(); // Assigns the reference to address of new
                      // instance of PointR allocated on the
                      // heap. The object on the heap uses 8
                      // bytes of memory for x and y, and an
                      // additional 8 bytes for core object
                      // requirements, such as storing the 
                      // object's type  synchronization state
    b = new PointV(); // Calls the value-type's default
                      // constructor.  The default constructor 
                      // for both PointR and PointV will set 
                      // each field to its default value, which 
                      // will be 0 for both x and y.
    a.x = 7;
    b.x = 7;
  }
}
// At the end of the method the local variables a and b go out of
// scope, but the new instance of a PointR remains in memory until
// the garbage collector determines it is no longer referenced

    ...
    PointR c = a;
    PointV d = b;
    c.x = 9;
    d.x = 9;
    Console.WriteLine(a.x); // Prints 9
    Console.WriteLine(b.x); // Prints 7
  }
}
Type System Unification
Value Types "Expand The Set Of Simple Types"

int[] iarr = new int [1000];

struct PointV {
  public int x, y
}
PointV[] pvarr = new PointV[1000];

class PointR {
   public int x, y;
}
PointR[] prarr = new PointR[1000];
for( int i=0; i<prarr.Length; i++ )
   prarr[i] = new PointR();
Boxing and Unboxing Value Types

class Queue {
  ...
  void Enqueue(object o) {...}
  object Dequeue() {return ...}
}

Queue q = new Queue();
q.Enqueue(9); // box the int
int i = (int)q.Dequeue(); // unbox the int

Variables

Definite Assignment

using System;
class Test {
  int v;
  // Constructors that initalize an instance of a Test
  public Test() {} // v will be automatically assigned to 0
  public Test(int a) { // explicitly assign v a value
     v = a;
  }
  static void Main() {
    Test[] iarr = new Test [2]; // declare array
    Console.WriteLine(iarr[1]); // ok, elements assigned to null
    Test t;
    Console.WriteLine(t); // error, t not assigned
  }
}
Default Values

int a = 1000000;
int b = 1000000;

// Check an expression
int c = checked(a*b);

// Check every expression in a statement-block
checked {
   ...
   c = a * b;
   ...
}

const int signedBit = unchecked((int)0x80000000);

Statements

Expression Statements

int x = 5 + 6; // assign result
x++; // side effect
int y = Math.Min(x, 20); // side effect and assign result
Math.Min (x, y); // discards result, but ok, there is a side effect
x == y; // error, has no side effect, and does not assign result
Declaration Statements

bool a = true;
while(a) {
   int x = 5;
   if (x==5) {
      int y = 7;
      int x = 2; // error, x already defined
   }
   Console.WriteLine(y); // error, y is out of scope
}

const double speedOfLight = 2.99792458E08;
speedOfLight+=10; // error
Empty Statements

while(!thread.IsAlive);
Selection Statements
If-Else Statement

int Compare(int a, int b) {
   if (a>b)
      return 1;
   else if (a<b)
      return -1;
   return 0;
}
Switch Statement

void Award(int x) {
  switch(x) {
    case 1:
      Console.WriteLine("Winner!");
      break;
    case 2:
      Console.WriteLine("Runner-up");
      break;
    case 3:
    case 4:
      Console.WriteLine("Highly commended");
      break;
    default:
      Console.WriteLine("Don't quit your day job!");
      break;
  }
}

void Greet(string title) {
  switch (title) {
    case null:
      Console.WriteLine("And you are?");
      goto default;
    case "King":
      Console.WriteLine("Greetings your highness");
      // error, should specify break, otherwise...
    default :
      Console.WriteLine("How's it hanging?");
      break;
  }
}
Loop Statements
While Loops

int i = 0;
while (i<5) {
  i++;
}
Do-While Loops

int i = 0;
do
  i++;
while (i<5);
For Loops

for (int i=0; i<10; i++)
  Console.WriteLine(i);

for (;;)
  Console.WriteLine("Hell ain't so bad");
Foreach Loops

foreach ( type-value in IEnumerable )
  statement or statement-block

for (int i=0; i<dynamite.Length; i++)
  Console.WriteLine(dynamite [i]);

foreach (Stick stick in dynamite)
  Console.WriteLine(stick);

IEnumerator ie = dynamite.GetEnumerator();
while (ie.MoveNext()) {
  Stick stick = (Stick)ie.Current;
  Console.WriteLine(stick);
}
Jump Statements
Break Statement

int x = 0;
while (true) {
  x++;
  if (x>5)
    break; // break from the loop
}
Continue Statement

int x = 0;
int y = 0;
while (y<100) {
  x++;
  if ((x%7)==0)
    continue; // continue with next iteration
  y++;
}
Goto Statement

int x = 4;
start:
x++;
if (x==5)
 goto start;
Return Statement

int CalcX(int a) {
  int x = a * 100;
  return x; // return to the calling method with value
}
Throw Statement

if (w==null)
  throw new Exception("w can't be null");

Organizing Types

Namespaces

namespace MyCompany.MyProduct.Drawing {
  class Point {int x, y, z}
  delegate void PointInvoker(Point p);
}
Nesting Namespaces

namespace MyCompany {
  namespace MyProduct {
    namespace Drawing {
      class Point {int x, y, z}
      delegate void PointInvoker(Point p);
    }
  }
}
Using A Type With Its Fully Qualified Name

namespace TestProject {
  class Test {
    static void Main() {
      MyCompany.MyProduct.Drawing.Point x;
    }
  }
}
Using Keyword

namespace TestProject {
  using MyCompany.MyProduct.Drawing;
  class Test {
    static void Main() {
      Point x;
    }
  }
}
Aliasing Types and Namespaces

using sys = System;        // Namespace alias
using txt = System.String; // Type alias
class Test {
  static void Main() {
    txt s = "Hello, World!";
    sys.Console.WriteLine(s); // Hello, World!
    sys.Console.WriteLine(s.GetType()); // System.String
  }
}

Inheritance


class Location { // Implicitly inherits from object
  string name;

  // The constructor that initializes Location
  public Location(string name) {
    this.name = name;
  }
  public string Name {get {return name;}}
  public void Display() {
    Console.WriteLine(Name);
  }
}
class URL : Location { // Inherit from Location
  public void Navigate() {
    Console.WriteLine("Navigating to "+Name);
  }
  // The constructor for URL, which calls Location's constructor
  public URL(string name) : base(name) {}
}
:
class Test {
  static void Main() {
    URL u = new URL("http://microsoft.com");
    u.Display();
    u.Navigate();
  }
}
Class Conversions

URL u = new URL();
Location l = u; // upcast
u = (URL)l; // downcast
As Operator

u = l as URL;
Is Operator

if (l is URL)
  ((URL)l).Navigate();
Polymorphism

class LocalFile : Location {
  public void Execute() {
    Console.WriteLine("Executing "+Name);
  }
  // The constructor for LocalFile, which calls URL's constructor
  public LocalFile(string name) : base(name) {}
}
class Test {
  static void Main() {
    URL u = new URL();
    LocalFile l = new LocalFile();
    Show(u);
    Show(l);
  }
  public static void Show(Location loc) {
    Console.Write("Location is: ");
    loc.Display();
  }
}
Virtual Function Members

class Location {
  public virtual void Display() {
    Console.WriteLine(Name);
    }
    ...
}
class URL : Location {
  // chop off the http:// at the start
  public override void Display() {
    Console.WriteLine(Name.Substring(6));
  }
  ...
}
Abstract Classes and Abstract Members

abstract class Location {
  public abstract void Launch();
}
class URL : Location {
  public override void Launch() {
    Console.WriteLine("Run Internet Explorer...");
  }
}
class LocalFile : Location {
  public override void Launch() {
    Console.WriteLine("Run Win32 Program...");
  }
}
Sealed Classes

sealed class Math {
  ...
}
Hiding Inherited Members

class B {
  public virtual void Foo() {}
}
class D : B {
  public override void Foo() {}
}
class N : D {
  public new void Foo() {} // hides D's Foo
}
N n = new N();
n.Foo(); // calls N's Foo
((D)n).Foo(); // calls D's Foo
((B)n).Foo(); // calls D's Foo
Versioning Virtual Function Members

class B { // written by the library people
  virtual void Foo() {...} // added in latest update
}
class D : B { // written by you
  void Foo() {...}
}

Access Modifiers


// Assembly1.dll
using System;
public class A {
  private int x=5;
  public void Foo() {Console.WriteLine (x);}
  protected static void Goo() {}
  protected internal class NestedType {}
}
internal class B {
  private void Hoo () {
    A a1 = new A (); // ok
    Console.WriteLine(a1.x); // error, A.x is private
    A.NestedType n; // ok, A.NestedType is internal
    A.Goo(); // error, A's Goo is protected
  }
}

// Assembly2.exe (references Assembly1.dll)
using System;
class C : A { // C defaults to internal
  static void Main() { // Main defaults to private
    A a1 = new A(); // ok
    a1.Foo(); // ok
    C.Goo(); // ok, inherits A's protected static member
    new A.NestedType(); // ok, A.NestedType is protected
    new B(); // error, Assembly 1's B is internal
    Console.WriteLine(x); // error, A's x is private
  }
}
Restrictions on Access Modifiers

Classes and Structs

Instance Members and Static Members

class Panda {
  string name;
  static string speciesName = "Ailuropoda melanoleuca";
  // Initializes Panda(See Instance Constructors)
  public Panda(string name) {
    this.name = name;
  }
  public void PrintName() {
    Console.WriteLine(name);
  }
  public static void PrintSpeciesName() {
    Console.WriteLine(speciesName);
  }
}
class Test {
  static void Main() {
    Panda.PrintSpeciesName(); // invoke static method
    Panda p = new Panda("Petey");
    p.PrintName(); // invoke instance method
  }
}
Fields

class MyClass {
  int x;
  float y = 1, z = 2;
  static readonly int MaxSize = 10;
  ...
}
Constants

public static double Circumference(double radius) {
  return 2 * Math.PI * radius;
}

public static double Circumference(double radius) {
  return 6.2831853071795862 * radius;
}
Properties

public class Well {
  decimal dollars; // private field
  public int Cents {
    get { return(int)(dollars * 100); }
    set {
      // value is an implicit variable in a set
      if (value>=0) // typical validation code
         dollars = (decimal)value/100;
    }
  }
}
class Test {
   static void Main() {
      Well w = new Well();
      w.Cents = 25; // set
      int x = w.Cents; // get
      w.Cents += 10; // get and set(throw a dime in the well)
   }
}
Indexers

public class ScoreList {
  int[] scores = new int [5];
  // indexer
  public int this[int index] {
    get {
      return scores[index]; }
    set {
      if(value >= 0 && value <= 10)
        scores[index] = value;
    }
  }
  // property (read-only)
  public int Average {
    get {
      int sum = 0;
      foreach(int score in scores)
        sum += score;
      return sum / scores.Length;
    }
  }
}
class IndexerTest {
  static void Main() {
    ScoreList sl = new ScoreList();
    sl[0] = 9;
    sl[1] = 8;
    sl[2] = 7;
    sl[3] = sl[4] = sl[1];
    System.Console.WriteLine(sl.Average);
  }
}
Methods
Passing Arguments By Value

static void Foo(int p) {++p;}
static void Main() {
  int x = 8;
  Foo(x); // make a copy of the value-type x
  Console.WriteLine(x); // x will still be 8
}
Ref Modifier

static void Foo(ref int p) {++p;}
static void Test() {
  int x = 8;
  Foo(ref x); // send reference of x to Foo
  Console.WriteLine(x); // x is now 9
}
Out Modifier

using System;
class Test {
  static void Split(string name, out string firstNames, 
                    out string lastName) {
     int i = name.LastIndexOf(' ');
     firstNames = name.Substring(0, i);
     lastName = name.Substring(i+1);
  }
  static void Main() {
    string a, b;
    Split("Nuno Bettencourt", out a, out b);
    Console.WriteLine("FirstName:{0}, LastName:{1}", a, b);
  }
}
Params Modifier

using System;
class Test {
  static int Add(params int[] iarr) {
    int sum = 0;
    foreach(int i in iarr)
      sum += i;
    return sum;
  }
  static void Main() {
    int i = Add(1, 2, 3, 4);
    Console.WriteLine(i); // 10
  }
}
Overloading Methods

void Foo(int x);
viod Foo(double x);
void Foo(int x, float y);
void Foo(float x, int y);
void Foo(ref int x);
void Foo(out int x);

void Foo(int x);
float Foo(int x); // compile error
void Goo (int[] x);
void Goo (params int[] x); // compile error
Operators
Implementing Value Equality

class Note {
  int value;
  public Note(int semitonesFromA) {
    value = semitonesFromA;
  }
  public static bool operator ==(Note x, Note y) {
    return x.value == y.value;
  }
  public static bool operator !=(Note x, Note y) {
    return x.value != y.value;
  }
  public override bool Equals(object o) {
    if(!(o is Note))
      return false;
    return this ==(Note)o;
  }
}
Note a = new Note(4);
Note b = new Note(4);
Object c = a;
Object d = b;

// To compare a and b by reference
Console.WriteLine((object)a ==(object)b; // false 

//To compare a and b by value:
Console.WriteLine(a == b); // true

//To compare c and d by reference:
Console.WriteLine(c == d); // false

//To compare c and d by value:
Console.WriteLine(c.Equals(d)); // true
Custom Implicit and Explicit Conversions

...
// Convert to hertz
public static implicit operator double(Note x) {
  return 440*Math.Pow(2,(double)x.value/12);
}

// Convert from hertz(only accurate to nearest semitone)
public static explicit operator Note(double x) {
  return new Note((int)(0.5+12*(Math.Log(x/440)/Math.Log(2))));
}
...

Note n =(Note)554.37; // explicit conversion
double x = n; // implicit conversion
Three-State Logic Operators

public struct SQLBoolean ... {
  ...
  public static bool operator true(SQLBoolean x) {
    return x.value == 1;
  }
  public static bool operator false(SQLBoolean x) {
    return x.value == -1;
  }
  public static SQLBoolean operator !(SQLBoolean x) {
    return new SQLBoolean(- x.value);
  }
  public bool IsNull {
    get { return value == 0;}
  }
  ...
}
class Test {
  void Foo(SQLBoolean a) {
    if (a)
      Console.WriteLine("True");
    else if (! a)
      Console.WriteLine("False");
    else
      Console.WriteLine("Null");
   }
}
Instance Constructors

class MyClass {
  public MyClass() {
    // initialization code
  }
}

class MyClass {
  public int x;
  public MyClass() : this(5) {}
  public MyClass(int v) {
    x = v;
  }
}
MyClass m1 = new MyClass();
MyClass m2 = new MyClass(10);
Console.WriteLine(m1.x) // 5
Console.Writeline(m2.x) // 10;
Calling Base Class Constructors

class B {
  public int x ;
  public B(int a) {
    x = a;
  }
  public B(int a, int b) {
    x = a * b;
  }
  // Notice how all of B's constructors need parameters
}
class D : B {
  public D() : this(7) {} // call an overloaded constructor
  public D(int a) : base(a) {} // call a base class constructor
}
Field Initialization Order

class MyClass {
  int x = 5;
}
Static Constructors

class Test {
   static Test() {
       Console.WriteLine("Test Initialized");
   }
}
Static Field Initialization Order

class Test {
  public static int x = 5;
  public static void Foo() {}
  static Test() {
    Console.WriteLine("Test Initialized");
  }
}
Non-Determinism Of Static Constructor Calls

class Test2 {
  public static void Foo() {}
  static Test() {
    Console.WriteLine("Test2 Initialized");
  }
}
Test.Foo();
Test2.Foo();
Self Referencing
this Keyword

class Dude {
  string name;
  public Test(string name) {
    this.name = name;
  }
  public void Introduce(Dude a) {
    if (a!=this)
      Console.WriteLine("Hello, I'm "+name);
  }
}
Base Keyword

class Hermit : Dude {
  public void new Introduce(Dude a) {
    base.TalkTo(a);
    Console.WriteLine("Nice Talking To You");
  }
}
Destructors and Finalizers

protected override void Finalize() {
  ...
  base.Finalize();
}
Nested Types

using System;
class A {
  int x = 3; // private member
  protected internal class Nested {// choose any access-level
    public void Foo () {
      A a = new A ();
      Console.WriteLine (a.x); //can access A's private members
    }
  }
}
class B {
  static void Main () {
    A.Nested n = new A.Nested (); // Nested is scoped to A
    n.Foo ();
  }
}
// an example of using "new" on a type declaration
class C : A {
   new public class Nested {} // hide inherited type member
}

Interfaces

Defining an Interface

public interface IDelete {
   void Delete();
}
Implementing an Interface

public class TextBox : IDelete {
   public void Delete() {...}
}
public class TreeView : IDelete {
   public void Delete() {...}
}

public class TextBox : Control, IDelete {...}
public class TreeView : Control, IDelete {...}
Using an Interface

class MyForm {
   ...
   void DeleteClick() {
      if (ActiveControl is IDelete) {
         IDelete d = (IDelete)ActiveControl;
         d.Delete();
      }
   }
}
Extending an Interface

ISuperDelete : IDelete {
   bool CanDelete {get;}
   event EventHandler CanDeleteChanged;
}
Explicit Interface Implementation

public interface IDesignTimeControl {
   ...
   object Delete();
}
public class TextBox : IDelete, IDesignTimeControl {
   ...
   void IDelete.Delete() {}
   object IDesignTimeControl.Delete() {...}
   // Note that explicitly implementing just one of them would
   // be enough to resolve the conflict
}

TextBox tb = new TextBox();
IDesignTimeControl idtc = (IDesignTimeControl)tb;
IDelete id = (IDelete)tb;
idtc.Delete();
id.Delete();
Reimplementing An Interface

public class RichTextBox : TextBox, IDelete {
   // TextBox's IDelete.Delete is not virtual (since explicit
   // interface implementations cannot be virtual)
   public void Delete() {}
}
Interface Conversions

interface IDelete {...}
interface IDesigntimeControl {...}
class TextBox : IDelete, IDesignTimeControl {...}
sealed class Timer : IDesignTimeControl {...}

TextBox tb1 = new TextBox ();
IDelete d = tb1; // implicit cast
IDesignTimeControl dtc = (IDesignTimeControl)d;
TextBox tb2 = (TextBox)dtc;
Timer t = (Timer)d; // illegal, a Timer can never implement IDelete

Arrays


char[] vowels = new char[] {'a','e','i','o','u'};
Console.WriteLine(vowels [1]); // Prints "e"
Multi-Dimensional Arrays

// rectangular
int [,,] matrixR = new int [3, 4, 5]; // creates 1 big cube
// jagged
int [][][] matrixJ = new int [3][][];
int [][][] matrixJ = new int [3][][];
for (int i = 0; i < 3; i++) {
   matrixJ[i] = new int [4][];
   for (int j = 0; j < 4; j++)
      matrixJ[i][j] = new int [5];
} 
// assign an element
matrixR [1,1,1] = matrixJ [1][1][1] = 7;
Local and Field Array Declarations

// single dimensional
for(int i = 0; i < vowels.Length; i++);
// multi-dimensional
for(int i = 0; i < matrixR.GetLength(2); i++);
Bounds Checking

Enums


public enum Direction {North, East, West, South}

Direction walls = Direction.East;

[Flags]
public enum Direction : byte {
   North=1, East=2, West=4, South=8
}
Direction walls = Direction.North | Direction.West;
if((walls & Direction.North) != 0)
    System.Console.WriteLine("Can't go north!");

Console.WriteLine(walls.Format()); // Displays "North|West"
Console.WriteLine(walls); // Calls walls.ToString, displays "5"

using System;
public enum Toggle : byte { Off=0, On=1 }
class TestEnum {
  static void Main() {
    Type t = Enum.GetUnderlyingType(typeof(Toggle));
    Console.WriteLine(t); // Prints "Byte"

    bool bDimmed = Enum.IsDefined(typeof(Toggle), "Dimmed");
    Console.WriteLine(bDimmed); // Prints "False"

    Toggle tog =(Switch)Enum.FromString(typeof(Toggle), "On");
    Console.WriteLine(tog); // Prints "1"
    Console.WriteLine(tog.Format()); // Prints "On"

    object[] oa = Enum.GetValues(typeof(Toggle));
    foreach(Toggle tog in oa) // Prints "On=1, Off=0"
      Console.WriteLine("{0}={1}", tog.Format(), tog); 
  }
}

Delegates


delegate bool Filter(string s);

class Test {
   static void Main() {
      Filter f = new Filter(FirstHalfOfAlphabet);
      Display(new String [] {"Ant","Lion","Yak"}, f);
   }
   static bool FirstHalfOfAlphabet(string s) {
      return "N".CompareTo(s) > 0;
   }
   static void Display(string[] names, Filter f) {
      int count = 0;
      foreach(string s in names)
         if(f(s)) // invoke delegate
            Console.WriteLine("Item {0} is {1}", count++, s);
   }
}
Multicast Delegates

delegate void MethodInvoker();
class Test {
   static void Main() {
       new Test(); // prints "Foo","Goo"
   }
   Test() {
      MethodInvoker m = null;
      m += new MethodInvoker(Foo);
      m += new MethodInvoker(Goo);
      m();
   }
   void Foo() {
      Console.WriteLine("Foo");
   }
   void Goo() {
      Console.WriteLine("Goo");
   }
}

Test {
   MethodInvoker m = null;
   m += new MethodInvoker(Foo);
   m -= new MethodInvoker(Foo);
   // m is now null
}
Delegates Compared With Interfaces

interface IFilter {
   bool Filter(string s);
}
class Test {
  class FirstHalfOfAlphabetFilter : IFilter {
    public bool Filter(string s) {
      return ("N".CompareTo(s) > 0);
    }      
  }
  static void Main() {
    FirstHalfOfAlphabetFilter f = new FirstHalfOfAlphabetFilter();
    Display(new string [] {"Ant", "Lion", "Yak"}, f);
  }
  static void Display(string[] names, IFilter f) {
    int count = 0;
    foreach (string s in names)
      if (f.Filter(s))
        Console.WriteLine("Item {0} is {1}", count++, s);
  }
}

Events

Defining a Delegate for an Event

delegate void MoveEventHandler(object source, MoveEventArgs e);
Storing Data for an Event with EventArgs

public class MoveEventArgs : EventArgs {
  public int newPosition;
  public bool cancel;
  public MoveEventArgs(int newPosition) {
    this.newPosition = newPosition;
  }
}
Declaring and Firing an Event

class Slider {
  int position;
  public event MoveEventHandler Move;
  public int Position {
    get { return position; }
    set {
      if (position != value) { // if position changed
        if (Move != null) { // if invocation list not empty
          MoveEventArgs args = new MoveEventArgs(value);
          Move(this, args); // fire event
  if (args.cancel)
            return;
        }
        position = value;
      }
    }  
  }
}
Acting on an Event with Event Handlers

class Form {
  static void Main() {
    Slider slider = new Slider();
    // register with the Move event
    slider.Move += new MoveEventHandler(slider_Move);
    slider.Position = 20;
    slider.Position = 60;
  }
  static void slider_Move(object source, MoveEventArgs e) {
    if(e.newPosition < 50)
      Console.WriteLine("OK");
    else {
      e.cancel = true;
      Console.WriteLine("Can't go that high!");
    }
  }
}
Events As Properties

public event MoveEventHandler Move {
  get {
    return (MoveEventHandler)myEventStorer["Move"];
  }
  set {
    myEventStore ["Move"] = value;
  }
}

Try Statements and Exceptions

Exceptions

public class File {
  ...
  public static StreamWriter CreateText(string s) {
    ...
    if (!Valid(s))      
      throw new IOException("Couldn't create...", ...);
      ...
  }
}
class Test {
  ...
  void Foo(object x) {
    StreamWriter sw = null;
    try {
      sw = File.CreateText("foo.txt");
      sw.Write(x.ToString());
    }
    catch(IOException ex) {
      Console.WriteLine(ex);
    }
    finally {
      if(sw != null)
        sw.Close();
    }
  }
}
Catch Statement

catch(IOException) { // don't specify variable
  Console.WriteLine("Couldn't create the foo!");
}
Catching System.Exception

catch {
  Console.WriteLine("Couldn't create the foo!");
}
Specifying Multiple Catch Clauses

try {...}
catch (NullReferenceException) {...}
catch (IOException) {...}
catch {...}

Attributes

Attribute Classes

[Serializable]
public class Foo {...}

class SerializableAttribute : Attribute {...}

[System.SerializableAttribute]
public class Foo {...}
Named and Positional Parameters

[Obsolete("Use Bar class instead", IsError=true)]
public class Foo {...}
Attribute Targets

[assembly:CLSCompliant(true)]
Specifying Multiple Attributes

[Serializable, Obsolete, CLSCompliant(false)]
public class Bar {...}

[Serializable] 
[Obsolete] 
[CLSCompliant(false)]
public class Bar {...}

[Serializable, Obsolete] 
[CLSCompliant(false)]
public class Bar {...}

Unsafe Code and Pointers

Unsafe Code

unsafe void RedFilter(int[,] bitmap) {
  const int length = bitmap.Length;
  fixed (int* b = bitmap) {
    int* p = b;
    for(int i = 0; i < length; i++)
      *p++ &= 0xFF;
  }
}
Fixed Statement

class Test {
  int x;
  static void Main() {
    Test test = new Test();
    unsafe {
       fixed(int* p = &test.x) { // pins Test
         *p = 9;
       }
       System.Console.WriteLine(test.x);
    }
  }
}
Pointer to Member Operator

struct Test {
   int x;
   unsafe static void Main() {
      Test test = new Test();
      Test* p = &test;
      p->x = 9;
      System.Console.WriteLine(test.x);
   }
}
The stackalloc Keyword

int* a = stackalloc int [10];
for (int i = 0; i < 10; ++i)
   Console.WriteLine(a[i]); // print raw memory
Pre-Processor Directives

#define DEBUG
class MyClass {
  int x;
  void Foo() {
  # if DEBUG
    Console.WriteLine("Testing: x = {0}", x);
  # endif
  ...
}

#define DEBUG = true

XML Documentation

C/C++-Style Comments

int x = 3; // this is a comment
MyMethod(); /* this is a
comment that spans two lines */
Documentation Comments

// Filename: DocTest.cs
using System;
class MyClass {
  /// <summary>
  /// The Foo method is called from
  ///   <see cref="Main">Main</see> 
  /// </summary>
  /// <mytag>Secret stuff</mytag>
  /// <param name="s">Description for s</param>
  static void Foo(string s) { Console.WriteLine(s); }
  static void Main() { Foo("42"); }
}  
XML Documentation Files

<?xml version="1.0"?>
<doc>
  <assembly>
    <name>DocTest</name>
  </assembly>
  <members>
    <member name="M:MyClass.Foo(System.String)">
      <summary>
      The Foo method is called from
        <see cref="M:MyClass.Main">Main</see> 
      </summary>
      <mytag>Secret stuff</mytag>
      <param name="s">Description for s</param>
     </member>
  </members>
</doc> 
Predefined XML Tags <summary>, <remarks>
<summary>description</summary> <remarks>description</remarks>
<param>
<param name="name">description</param>
<returns>
<returns>description</returns>
<exception>
<exception [cref="type"]>description</exception>
<permission>
<permission [cref="type"]>description </permission>
The C# compiler supports the following XML tags.<example>, <c>, <code>
<example>description</example> <c>code</c> <code>code</code>
<see>, <seealso>
<see cref="member">text</see> <seealso cref="member">text</seealso>
<value>
<value>description</value>
<paramref>
<paramref name="name"/>
<list>, <para>
<list type=[ bullet | number | table ]>
  <listheader>
    <term>name</term>
    <description>description</description>
  </listheader>
  <item>
    <term>name</term>
    <description>description</description>
  </item>
</list>
<para>text</para>
Type or Member Cross-References

// Namespaces do not have independent signatures
namespace NS {
  // T:NS.MyClass
  class MyClass {
    // F:NS.MyClass.aField
    string aField;
    // P:NS.MyClass.aProperty
    short aProperty {get {...} set {...}}
    // T:NS.MyClass.NestedType
    class NestedType {...};
    // M:NS.MyClass.X()
    void X() {...}
    // M:NS.MyClass.Y(System.Int32,System.Double@,System.Decimal@)
    void Y(int p1, ref double p2, out decimal p3) {...}
    // M:NS.MyClass.Z(System.Char[],System.Single[0:,0:])
    void Z(char[] p1, float[,] p2) {...}
    // M:NS.MyClass.op_Addition(NS.MyClass,NS.MyClass)
    public static MyClass operator+(MyClass c1, MyClass c2) {...}
    // M:NS.MyClass.op_Implicit(NS.MyClass)~System.Int32
    public static implicit operator int(MyClass c) {...}
    // M:NS.MyClass.#ctor
    MyClass() {...}
    // M:NS.MyClass.Finalize
    ~MyClass() {...}
    // M:NS.MyClass.#cctor
    static MyClass() {...}
  }
}

Programming the .NET Framework

Common Types

Object Class
public class Object {
  public Object() {...}
  public virtual bool Equals(object o) {...}
  public virtual int GetHashCode(){...}
  public Type GetType(){...}
  public virtual string ToString() {...}
  protected virtual void Finalize() {...}
  protected object MemberwiseClone() {...}
}

using System;
class Beeblebrox {}
class Test {
  static void Main() {
    string s = "Zaphod";
    Beeblebrox b = new Beeblebrox();
    Console.WriteLine(s); // Prints "Zaphod"
    Console.WriteLine(b); // Prints "Beeblebrox"
  }
}
Creating BCL-Friendly Types

public class Point3D {
  public int x, y, z;
  public Point3D(int x, int y, int z) {
    this.x=x; this.y=y; this.z=z; // Initialize data
  }
  public override bool Equals(object o) {
    if (!(o is Point3D)) // Check for type equivalence
      return false;
    return (this==(Point3D)o); // Implemented by operator==
  }
  public static bool operator !=(Point3D lhs, Point3D rhs) {
    return (!(lhs==rhs)); // Implemented by operator==
  }
  public static bool operator ==(Point3D lhs, Point3D rhs) {
    return ((rhs.x==lhs.x) && (rhs.y==lhs.y) && (rhs.z==lhs.z));
  }
  public override int GetHashCode(){
    return x^y^z;
  }
  public override string ToString() {
    return String.Format("[{0},{1},{2}]", x, y, z);
  }
}

using System;
using System.Collections;
public class Point3D {...}
class TestPoint3D {
  static void Main() {
    // Uses ToString, prints "p1=[1,1,1] p2=[2,2,2] p3=[2,2,2]"
    Point3D p1 = new Point3D(1,1,1);
    Point3D p2 = new Point3D(2,2,2);
    Point3D p3 = new Point3D(2,2,2);
    Console.WriteLine("p1={0} p2={1} p3={2}", p1, p2, p3);

    // Tests for equality to demonstrate Equals, == & !=
    int i = 100;
    Console.WriteLine(p1.Equals(i)); // Prints "False"
    Console.WriteLine(p1==p2); // Prints "False"
    Console.WriteLine(p2==p3); // Prints "True"

    // Use a hashtable to store points (uses GetHashCode)
    Hashtable ht = new Hashtable();
    ht["p1"] = p1; 
    ht["p2"] = p2;
    ht["p3"] = p3;

    // Prints "p2=[2,2,2] p3=[2,2,2] p1=[1,1,1]"
    foreach (DictionaryEntry de in ht)
      Console.Write("{0}={1} ", de.Key, de.Value);  
  }
}
ICloneable Interface

public interface ICloneable {
  object Clone();
}

public class A : ICloneable {
   int x;
   public object Clone() {
       return MemberwiseClone();
   }
}
IComparable Interface

interface IComparable {
  int CompareTo(object o);
}

using System;
using System.Collections;
class MyType : IComparable {
  public int x;
  public MyType(int x) {
    this.x = x;
  }
  public int CompareTo(object o) {
    return x -((MyType)o).x;
  }
}
class Test {
  static void Main() {
    ArrayList a = new ArrayList();
    a.Add(new MyType(42));
    a.Add(new MyType(17));
    a.Sort();
    foreach(MyType t in a)
      Console.WriteLine(((MyType)t).x);
   }
}
IFormattable Interface

public interface IFormattable {
  string Format(string format, IServiceObjectProvider sop);
}

Math

Language Support for Math

struct Vector {
  float direction;
  float magnitude;
  public Vector(float direction, float magnitude) {
    this.direction = direction;
    this.magnitude = magnitude;
  }
  public static Vector operator *(Vector v, float scale) {
    return new Vector(v.direction, v.magnitude * scale);
  }
  public static Vector operator /(Vector v, float scale) {
    return new Vector(v.direction, v.magnitude * scale);
  }
  ...
}
class Test {
  static void Main() {
  Vector [,] matrix = {{new Vector(1f,2f), new Vector(6f,2f)},
                       {new Vector(7f,3f), new Vector(4f,9f)}};
  for (int i=0; i<matrix.GetLength(0); i++)
    for (int j=0; j<matrix.GetLength(1); j++)
      matrix[i, j] *= 2f;
}
Special Types and Operators
Math Class

using System;
class Test {
  static void Main() {
    double a = 3;
    double b = 4;
    double C = Math.PI / 2;
    double c = Math.Sqrt (a*a+b*b-2*a*b*Math.Cos(C));
    Console.WriteLine("The length of side c is "+c);
  }
}
Random Class

Random r = new Random();
Console.WriteLine(r.Next(50)); // return between 0 and 50

Strings

Immutability of Strings

string a = "Heat";
string b = a.Insert(3, "r");
Console.WriteLine(b); // Prints Heart
If you need a mutable string, see the StringBuilder class.
String Interning

string a = "hello";
string b = "hello";
Console.WriteLine(a == b); // True
Console.WriteLine(a.Equals(b)); // True
Console.WriteLine((object)a == (object)b); // True!!
Formatting Strings

using System;
class TestFormatting {
  static void Main() {
    int i = 2;
    decimal m = 42.73m;
    string s = String.Format("Account {0} has {1:C}.", i, m);
    Console.WriteLine(s); // Prints "Account 2 has $42.73"
  }
}
Indexing Strings

using System;
class TestIndexing {
  static void Main() {
    string s = "Going down?";
    for (int i=0; i<s.Length; i++)
      Console.WriteLine(s[i]); // Prints s vertically
  }
}
Encoding Strings

using System;
using System.Text;
class TestEncoding {
  static void Main() {
    byte[] ba = new byte[] { 67, 35, 32, 105, 115, 
                             32, 67, 79, 79, 76, 33 };
    string s = Encoding.ASCII.GetString(ba);
    Console.WriteLine(s);
  }
} 
StringBuilder Class

using System;
using System.Text;
class TestStringBuilder {
  static void Main() {
    StringBuilder sb = new StringBuilder("Hello, ");
    sb.Append("World");
    sb[11] = '!';
    Console.WriteLine(sb); // Hello, World!
  }
}

Collections

ArrayList Class

ArrayList a = new ArrayList();
a.Add("Vernon");
a.Add("Corey");
a.Add("William");
a.Add("Muzz");
a.Sort();
for(int i = 0; i < a.Count; i++)
   Console.WriteLine(a [i]);
BitArray Class

BitArray bits = new BitArray();
bits.Length = 2;
bits[1] = true;
bits.Xor(bits); // Xor the array with itself
Hashtable Class

Hashtable ht = new Hashtable();
ht["One"] = 1;
ht["Two"] = 2;
ht["Three"] = 3;
Console.WriteLine(ht["Two"]); // Prints "2"
Queue Class

Queue q = new Queue();
q.Enqueue(1);
q.Enqueue(2);
Console.WriteLine(q.Dequeue()); // Prints "1"
Console.WriteLine(q.Dequeue()); // Prints "2"
SortedList Class

SortedList s = new SortedList();
s["Zebra"] = 1;
s["Antelope"] = 2;
s["Eland"] = 3;
s["Giraffe"] = 4;
s["Meerkat"] = 5;
s["Dassie"] = 6;
s["Tokoloshe"] = 7;
Console.WriteLine(s["Meerkat"]); // Prints "5" in 3 lookups
Stack Class
Stack s = new Stack();
s.Push(1); // Stack = 1
s.Push(2); // Stack = 1,2
s.Push(3); // Stack = 1,2,3
Console.WriteLine(s.Pop()); // Prints 3, Stack=1,2
Console.WriteLine(s.Pop()); // Prints 2, Stack=1
Console.WriteLine(s.Pop()); // Prints 1, Stack=
StringCollection Class

StringCollection sc = new StringCollection();
sc.Add("s1");
string[] sarr =  {"s2", "s3", "s4"};
sc.AddRange(sarr);
foreach (string s in sc)
  Console.Write("{0} ", s); // s1 s2 s3 s4
Collection Interfaces

IEnumerable
public interface IEnumerable {
  IEnumerator GetEnumerator();
}
IEnumerator

public interface IEnumerator {
   bool MoveNext();
   object Current {get;}
   void Reset();
}

using System.Collections;
public class MyCollection : IEnumerable {
  // ...
  public virtual IEnumerator GetEnumerator () {
    return new MyCollection.Enumerator(this);
  }
  private class Enumerator : IEnumerator { 
    private MyCollection collection;
    private int currentIndex = -1;

    internal Enumerator (MyCollection collection) {
      this.collection = collection;
    }
    public object Current {
      get {
        if (currentIndex == collection.Count)
          throw new InvalidOperationException();
        return collection [currentIndex];
      }
    }
    public bool MoveNext () {
      if (currentIndex > collection.Count)
        throw new InvalidOperationException();
      return ++currentIndex < collection.Count;
    }
    public void Reset () {
      currentIndex = -1;
    }
  }
}

MyCollection mcoll = new MyCollection();
...
// Using foreach: substitute your typename for XXX
foreach (XXX item in mcoll) {
  Console.WriteLine(item);
  ...
}
// Using IEnumerator: substitute your typename for XXX
IEnumerator ie = myc.GetEnumerator();
while (myc.MoveNext()) {
  XXX item = (XXX)myc.Current;
  Console.WriteLine(item);
  ...
}
ICollection Interface

public interface ICollection : IEnumerable {
   void CopyTo(Array array, int index);
   int Count {get;}
   bool IsReadOnly {get;}
   bool IsSynchronized {get;}
   object SyncRoot {get;}
}
IComparer Interface
public interface IComparer {
   int Compare(object x, object y);
}
IList Interface

public interface IList : ICollection, IEnumerable {
   object this [int index] {get; set}
   int Add(object o);
   void Clear();
   bool Contains(object value);
   int IndexOf(object value);
   void Insert(int index, object value);
   void Remove(object value);
   void RemoveAt(int index);
}
IDictionary Interface

public interface IDictionary : ICollection, IEnumerable {
   object this [object key] {get; set};
   ICollection Keys {get;}
   ICollection Values {get;}
   void Clear();
   bool Contains(object value);
   IDictionaryEnumerator GetEnumerator();
   void Remove(object key);
}
IDictionaryEnumerator Interface

public interface IDictionaryEnumerator : IEnumerator {
   DictionaryEntry Entry {get;}
   object Key {get;}
   object Value {get;}
}
IHashCodeProvider Interface

public interface IHashCodeProvider {
   int GetHashCode(object o);
}

Regular Expressions

Using Regular Expressions

// RegEx.cs - compile with /r:System.Text.RegularExpressions.dll
using System;
using System.Text.RegularExpressions;
class TestRegEx {
  static void Main() {
    string pat =
@"(?<1>[^\+!?#]*)(?<2>\+)?[^!?#]*?(?<3>#)?(?<4>[!?]?!|\?)?(?<3>#)?";

    string t = "e8=Q+#!!";
    Regex regex = new Regex(pat);
    Match m = regex.Match(t);
    if(m == null)
      System.Console.WriteLine("No Match");
    else
      System.Console.Write(
        "Group 1 = "+ m.Group(1).ToString() + "\n" +
        "Group 2 = "+ m.Group(2).ToString() + "\n" +
        "Group 3 = "+ m.Group(3).ToString() + "\n" +
        "Group 4 = "+ m.Group(4).ToString() + "\n");
  }
}

Group 1 = e8=Q
Group 2 = +
Group 3 = #
Group 4 = !!

Input/Output

Concrete Stream-Derived Classes

using System.IO;
class Test {
  static void Main() {
    Stream s = new FileStream("foo.txt", Filemode.Create);
    s.WriteByte("67");
    s.WriteByte("35");
    s.Close();
  }
}
StreamReader and StreamWriter Classes

using System.Text;
using System.IO;
class Test {
  static void Main() {
    Stream fs = new FileStream ("foo.txt", FileMode.Create);
    StreamWriter sw = new StreamWriter(fs, Encoding.ASCII);
    sw.Write("Hello!");
    sw.Close();
  }
}
StringReader and StringWriter Classes

using System;
using System.IO;
using System.Text;
class Test {
  static void Main() {
    StringBuilder sb = new StringBuilder();
    StringWriter sw = new StringWriter(sb);
    WriteHello(sw);
    Console.WriteLine(sb);
  }
  static void WriteHello(TextWriter tw) {
    tw.Write("Hello, String I/O!");
  }
}
Directories and Files

using System;
using System.IO;
class Test {
   static void Main(string[] args) {
      Stream s = File.OpenRead(args[0]);
      StreamReader sr = new StreamReader(s);
      Console.WriteLine(sr.ReadLine());
      sr.Close();
   }
}

Networking

Generic Request/Response Architecture

// Snarf.cs - compile with /r:System.Net.dll
// Run Snarf.exe <http-uri> to retrieve a web page
using System;
using System.IO;
using System.Net;
using System.Text;
class Snarf {
  static void Main(string[] args) {

    // Retrieve the data at the URL with an WebRequest ABC
    WebRequest req = WebRequestFactory.Create(args[0]);
    WebResponse resp = req.GetResponse();

    // Read in the data, performing ASCII->Unicode encoding
    Stream s = resp.GetResponseStream();
    StreamReader sr = new StreamReader(s, Encoding.ASCII);
    string doc = sr.ReadToEnd();

    Console.WriteLine(doc); // Print result to console
  }
}
HTTP-Specific Support

// ProbeSvr.cs - compile with /r:System.Net.dll
// Run ProbeSvr.exe <servername> to retrieve the server type
using System;
using System.Net;
class ProbeSvr {
  static void Main(string[] args) {

    // Get instance of WebRequest ABC, convert to HttpWebRequest
    WebRequest req = WebRequestFactory.Create(args[0]);
    HttpWebRequest httpReq = (HttpWebRequest)req;

    // Access HTTP-specific features such as User-Agent
    httpReq.UserAgent = "CSPRProbe/1.0";

    // Retrieve response and print to console
    WebResponse resp = req.GetResponse();
    HttpWebResponse httpResp = (HttpWebResponse)resp;
    Console.WriteLine(httpResp.Server);
  }
}

// QOTDListener.cs - compile with /r:System.Net.dll 
// Run QOTDListener.exe to service incoming QOTD requests
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class QOTDListener {
  static string[] quotes = 
{@"Sufficiently advanced magic is indistinguishable from technology -- Terry Pratchett",
 @"Sufficiently advanced technology is indistinguishable from magic -- Arthur C Clarke" };
  static void Main() {

    // Start a TCP listener on port 17
    TCPListener l = new TCPListener(17);
    l.Start();
    Console.WriteLine("Waiting for clients to connect");
    Console.WriteLine("Press Ctrl+C to quit...");
    int numServed = 1;
    while (true) {

      // Block waiting for an incoming socket connect request
      Socket s = l.Accept();

      // Encode alternating quotes as bytes for sending 
      Char[] carr = quotes[numServed%2].ToCharArray();
      Byte[] barr = Encoding.ASCII.GetBytes(carr);

      // Return data to client, then clean up socket & repeat
      s.Send(barr, barr.Length, 0);
      s.Shutdown(SocketShutdown.SdBoth);
      s.Close();
      Console.WriteLine("{0} quotes served...", numServed++);
    }
  }
}
Using DNS

// DNSLookup.cs - compile with /r:System.Net.dll
// Run DNSLookup.exe <servername> to determine IP addresses
using System;
using System.Net;
class DNSLookup {
  static void Main(string[] args) {
    IPHostEntry he = DNS.GetHostByName(args[0]);
    IPAddress[] addrs = he.AddressList;
    foreach (IPAddress addr in addrs)
      Console.WriteLine(addr);
  }
}

Threading


using System;
using System.Threading;
class ThreadTest {
  static void Main() {
  Thread t = new Thread(new ThreadStart(Go));
    t.Start();
    Go();
  }
  static void Go() {
    for (char c='a'; c<='z'; c++ )
      Console.Write(c);
  }
}

abcdabcdefghijklmnopqrsefghjiklmnopqrstuvwxyztuvwxyz
Thread Synchronization
The Lock Statement

using System;
using System.Threading;
class LockTest {
  static void Main() {
    LockTest lt = new LockTest ();
    Thread t = new Thread(new ThreadStart(lt.Go));
    t.Start();
    lt.Go();
  }
  void Go() {
    lock(this)
      for ( char c='a'; c<='z'; c++)
        Console.Write(c);
  }
}

abcdefghijklmnopqrstuvwzyzabcdefghijklmnopqrstuvwzyz

System.Threading.Monitor.Enter(expression);
try {
  ...
}
finally {
  System.Threading.Monitor.Exit(expression);
}
Pulse and Wait

using System;
using System.Threading;
class MonitorTest {
  static void Main() {
    MonitorTest mt = new MonitorTest();
    Thread t = new Thread(new ThreadStart(mt.Go));
    t.Start();
    mt.Go();
  }
  void Go() {
    for ( char c='a'; c<='z'; c++)
      lock(this) {
        Console.Write(c);
        Monitor.Pulse(this);
        Monitor.Wait(this);
      }
  }
}

aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
Deadlocks

  void Go() {
    for ( char c='a'; c<='z'; c++)
      lock(this) {
        Console.Write(c);
        Monitor.Pulse(this);
        if (c<'z')
          Monitor.Wait(this);
      }
  }

Reflection

Retrieving a Type Directly

Type t = Type.GetType("System.Int32");

Type t = typeof(System.Int32);
Reflecting Over a Type Hierarchy

using System;
using System.Reflection;
class Test {
  static void Main() {
    object o = new Object();
    DumpTypeInfo(o.GetType());
    DumpTypeInfo(typeof(int));
    DumpTypeInfo(Type.GetType("System.String"));
  }
  static void DumpTypeInfo(Type t) {
    Console.WriteLine("Type: {0}", t);

    // Retrieve the list of members in the type
    MemberInfo[] miarr = t.GetMembers(BindingFlags.LookupAll);

    // Print out details on each of them
    foreach (MemberInfo mi in miarr)
      Console.WriteLine("  {0}={1}", mi.MemberType.Format(), mi);
  }
}
Late Binding to Types

// Greeting.cs - compile with /t:library
public abstract class Greeting { 
  public abstract void SayHello();
}

// English.cs - compile with /t:library /r:Greeting.dll
using System;
public class AmericanGreeting : Greeting {
  private string msg = "Hey, dude. Wassup!";
  public override void SayHello() {
    Console.WriteLine(msg);
  }
}
public class BritishGreeting : Greeting {
  private string msg = "Good morning, old chap!";
  public override void SayHello() {
    Console.WriteLine(msg);
  }
}

// SayHello.cs - compile with /r:Greeting.dll
// Run with SayHello.exe <dllname1> <dllname2> ... <dllnameN>
using System;
using System.Reflection;
class Test {
  static void Main (string[] args) {

    // Iterate over the cmd-line options,
    // trying to load each assembly
    foreach (string s in args) {
      Assembly a = Assembly.LoadFrom(s);
      
      // Pick through all the public type, looking for
      // subtypes of the abstract base class Greeting
      foreach (Type t in a.GetTypes())
        if (t.IsSubclassOf(typeof(Greeting))) {

          // Having found an appropriate subtype, create it
          object o = Activator.CreateInstance(t);

          // Retrieve the SayHello MethodInfo & invoke it
          MethodInfo mi = t.GetMethod("SayHello");
          mi.Invoke(o, null);
        }
    }
  }
}

Hey, dude. Wassup!
Good morning, old chap!
Forms of Activation

object o = Activator.CreateInstance("Assem1.dll",              
                                    "Friendly.Greeting");
Advanced Uses of Reflection

// InControl.cs - compile with /r:Greeting.dll,English.dll
using System;
using System.Reflection;
class TestReflection {
  // Note: This method requires the ReflectionPermission perm.
  static void ModifyPrivateData(object o, string msg) {

    // Get a FieldInfo type for the private data member
    Type t = o.GetType(); 
    FieldInfo fi = t.GetField("msg", BindingFlags.NonPublic|
                                     BindingFlags.Instance);

    // Use the FieldInfo to adjust the data member value
    fi.SetValue(o, msg);
  }
  static void Main() {
    // Create instances of both types
    BritishGreeting bg = new BritishGreeting();
    AmericanGreeting ag = new AmericanGreeting();

    // Adjust the private data via reflection
    ModifyPrivateData(ag, "Things are not the way they seem");
    ModifyPrivateData(bg, "The runtime is in total control!");
    
    // Display the modified greeting strings
    ag.SayHello(); // "Things are not the way they seem"
    bg.SayHello(); // "The runtime is in total control!"
  }
}

Things are not the way they seem
The runtime is in total control!
Creating New Types at Runtime

using System;
using System.Reflection;
using System.Reflection.Emit;
public class Test
{
  static void Main()
  {
    // Create a dynamic assembly in the current AppDomain
    AppDomain ad = AppDomain.CurrentDomain;
    AssemblyName an = new AssemblyName();
    an.Name = "DynAssembly";
    AssemblyBuilder ab = 
      ad.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
    
    // Create a module in the assembly & a type in the module
    Assembly a = (Assembly)ab;
    ModuleBuilder modb = a.DefineDynamicModule("DynModule");
    TypeBuilder tb = modb.DefineType("AgentSmith", 
                                     TypeAttributes.Public);
 
    // Add a SayHello member to the type 
    MethodBuilder mb = tb.DefineMethod("SayHello",        
                                       MethodAttributes.Public,
                                       null, null);
                                        
    // Generate the MSIL for the SayHello Member
    ILGenerator ilg = mb.GetILGenerator();
    ilg.EmitWriteLine("Never send a human to do a machine's job.");
    ilg.Emit(OpCodes.Ret);

    // Finalize the type so we can create it
    tb.CreateType();

    // Create an instance of the new type
    Type t = Type.GetType("AgentSmith");
    object o = Activator.CreateInstance(t);
    
    // Prints "Never send a human to do a machine's job."
    t.GetMethod("SayHello").Invoke(o, null);
  }
}

Custom Attributes

Defining a New Custom Attribute

using System;
[AttributeUsage(AttributeTargets.ClassMembers, AllowMultiple=true)]
class CrossRefAttribute : Attribute {
  Type   xref;
  string desc = "";
  public string Description { set { desc=value; } } 
  public CrossRefAttribute(Type xref) { this.xref=xref; }
  public override string ToString() {
    string tmp = (desc.Length>0) ? " ("+desc+")" : "";
    return "CrossRef to "+xref.ToString()+tmp;
  }   
}

[CrossRef(typeof(Bar), Description="Foos often hang around Bars")]
class Foo {...}
Retrieving a Custom Attribute at Runtime

using System;
[Serializable, Obsolete]
class Test {
  static void Main() {
    Type t = typeof(Test);
    object[] caarr = t.GetCustomAttributes();
    Console.WriteLine("{0} has {1} custom attribute(s)",
                      t, caarr.Length);
    foreach (object ca in caarr)
      Console.WriteLine(ca);
  }
}

Test has 1 custom attribute(s)
System.ObsoleteAttribute
Dispose and Close Methods

public class Worker {
  ...
  public void Dispose() {
    // Perform normal cleanup
    ... 
    // Mark this object finalized
    GC.SuppressFinalize(this);
  }
  protected override void Finalize() {
    Dispose();
    base.Finalize();
  }
}

Interop With Native DLLs


int MessageBox(HWND hWnd, LPCTSTR lpText, 
               LPCTSTR lpCation, UINT uType);

using System.Runtime.InteropServices;
[DllImport("user32.dll")]
static extern int MessageBox(int hWnd, string text, 
                             string caption, int type);
Marshaling Common Types
using System.Runtime.InteropServices;
static extern int Foo([MarshalAs(UnmanagedType.LPStr)]
                      string s);

using System.Runtime.InteropServices;
[DllImport("kernel32.dll")]
static extern int GetWindowsDirectory(StringBuilder sb,
                                      int maxChars);
class Test {
   static void Main() {
      StringBuilder s = new String(256);
      GetWindowsDirectory(s, 256);
      Console.WriteLine(s);
   }
}
Marshalling Classes and Structs

using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
class SystemTime {
   public ushort wYear; 
   public ushort wMonth;
   public ushort wDayOfWeek; 
   public ushort wDay; 
   public ushort wHour; 
   public ushort wMinute; 
   public ushort wSecond; 
   public ushort wMilliseconds; 
}
class Test {
   [DllImport("kernel32.dll")]
   static extern void GetSystemTime(SystemTime t);
   static void Main() {
      SystemTime t = new SystemTime();
      GetSystemTime(t);
      Console.WriteLine(t.wYear);
   }
}
In and Out Marshaling

struct SystemTime {...}
static extern void GetSystemTime(ref SystemTime t);

static extern void Foo([in] int[] array);
Callbacks from Unmanaged Code

class Test {
   delegate bool CallBack(int hWnd, int lParam);
   [DllImport("user32.dll")]
   static extern int EnumWindows(CallBack hWnd, int lParam);
   static bool PrintWindow(int hWnd, int lParam) {
      Console.WriteLine(hWnd);
      return true;
   }
   static void Main() {
      CallBack e = new CallBack(PrintWindow);
      EnumWindows(e, 0);
   }
}

Interop With COM

Exposing COM Objects To C#

// IMAdd.cs - compile with /r:Messenger.dll
// Run IMAdd.exe <UserID> to add an MSN Instant 
//   Messenger user to Contacts
// Run TlbImp.exe "C:\Program Files\Messenger\msmsgs.exe" 
//   to create Messenger.dll
using System.Runtime.InteropServices;
using Messenger; // COM API for MSN Instant Messenger
class COMConsumer {
   static void Main(string[] args) {
      MessengerApp m = new MessengerApp()
      m.LaunchAddContactUI(args[0]);
   }
}
Exposing C# Objects To COM

[GuidAttribute("aa6b10a2-dc4f-4a24-ae5e-90362c2142c1")]
public interface : IRunInfo {
  [DispId(1)]
  string GetRunInfo();
}
[GuidAttribute("b72ccf55-88cc-4657-8577-72bd0ff767bc")]
public class StackSnapshot : IRunInfo {
  public StackSnapshot() {
    st = new StackTrace();
  }
  [DispId(1)]
  public string GetRunInfo() {
    return st.ToString();
  }
  private StackTrace st;
}

Regular Expressions

using System;
class TestDefaultFormats {
  static void Main() {
    int i = 654321;
    Console.WriteLine("{0:C}", i); // $654,321.00
    Console.WriteLine("{0:D}", i); // 654321
    Console.WriteLine("{0:E}", i); // 6.543210E+005
    Console.WriteLine("{0:F}", i); // 654321.00
    Console.WriteLine("{0:G}", i); // 654321
    Console.WriteLine("{0:N}", i); // 654,321.00
    Console.WriteLine("{0:X}", i); // 9FBF1
    Console.WriteLine("{0:x}", i); // 9fbf1
  }
}

using System;
class TestIntegerFormats {
  static void Main() {
    int i = 123;
    Console.WriteLine("{0:C6}", i); // $123.000000
    Console.WriteLine("{0:D6}", i); // 000123
    Console.WriteLine("{0:E6}", i); // 1.230000E+002
    Console.WriteLine("{0:G6}", i); // 123
    Console.WriteLine("{0:N6}", i); // 123.000000
    Console.WriteLine("{0:X6}", i); // 00007B
    i = -123;
    Console.WriteLine("{0:C6}", i); // ($123.000000)
    Console.WriteLine("{0:D6}", i); // -000123
    Console.WriteLine("{0:E6}", i); // -1.230000E+002
    Console.WriteLine("{0:G6}", i); // -123
    Console.WriteLine("{0:N6}", i); // -123.000000
    Console.WriteLine("{0:X6}", i); // FFFF85
    i = 0;
    Console.WriteLine("{0:C6}", i); // $0.000000
    Console.WriteLine("{0:D6}", i); // 000000
    Console.WriteLine("{0:E6}", i); // 0.000000E+000
    Console.WriteLine("{0:G6}", i); // 0
    Console.WriteLine("{0:N6}", i); // 0.000000
    Console.WriteLine("{0:X6}", i); // 000000
  }
}                                                

using System;
class TestDoubleFormats {
  static void Main() {
    double d = 1.23;
    Console.WriteLine("{0:C6}", d); // $1.230000
    Console.WriteLine("{0:E6}", d); // 1.230000E+000
    Console.WriteLine("{0:G6}", d); // 1.23
    Console.WriteLine("{0:N6}", d); // 1.230000
    d = -1.23;
    Console.WriteLine("{0:C6}", d); // ($1.230000)
    Console.WriteLine("{0:E6}", d); // -1.230000E+000
    Console.WriteLine("{0:G6}", d); // -1.23
    Console.WriteLine("{0:N6}", d); // -1.230000
    d = 0;
    Console.WriteLine("{0:C6}", d); // $0.000000
    Console.WriteLine("{0:E6}", d); // 0.000000E+000
    Console.WriteLine("{0:G6}", d); // 0
    Console.WriteLine("{0:N6}", d); // 0.000000
  }
}

using System;
class TestIntegerCustomFormats {
  static void Main() {
    int i = 123;
    Console.WriteLine("{0:#0}", i);             // 123
    Console.WriteLine("{0:#0;(#0)}", i);        // 123
    Console.WriteLine("{0:#0;(#0);<zero>}", i); // 123
    Console.WriteLine("{0:#%}", i);             // 12300%
    i = -123;
    Console.WriteLine("{0:#0}", i);             // -123
    Console.WriteLine("{0:#0;(#0)}", i);        // (123)
    Console.WriteLine("{0:#0;(#0);<zero>}", i); // (123)
    Console.WriteLine("{0:#%}", i);             // -12300%
    i = 0;
    Console.WriteLine("{0:#0}", i);             // 0
    Console.WriteLine("{0:#0;(#0)}", i);        // 0
    Console.WriteLine("{0:#0;(#0);<zero>}", i); // <zero>
    Console.WriteLine("{0:#%}", i);             // %
  }
}

using System;
class TestDoubleCustomFormats {
  static void Main() {
    double d = 1.23;
    Console.WriteLine("{0:#.000E+00}", d);    // 1.230E+00
    Console.WriteLine(
      "{0:#.000E+00;(#.000E+00)}", d);        // 1.230E+00
    Console.WriteLine(
      "{0:#.000E+00;(#.000E+00);<zero>}", d); // 1.230E+00
    Console.WriteLine("{0:#%}", d);           // 123%
    d = -1.23;
    Console.WriteLine("{0:#.000E+00}", d);    // -1.230E+00
    Console.WriteLine(
      "{0:#.000E+00;(#.000E+00)}", d);        // (1.230E+00)
    Console.WriteLine(
      "{0:#.000E+00;(#.000E+00);<zero>}", d); // (1.230E+00)
    Console.WriteLine("{0:#%}", d);          // -123%
    d = 0;
    Console.WriteLine("{0:#.000E+00}", d);    // 0.000E-01
    Console.WriteLine(
      "{0:#.000E+00;(#.000E+00)}", d);        // 0.000E-01
    Console.WriteLine(
      "{0:#.000E+00;(#.000E+00);<zero>}", d); // <zero>
    Console.WriteLine("{0:#%}", d);           // %
  }
}

DateTime Format Specifiers


using System;
class TestDateTimeFormats {
  static void Main() {
    DateTime dt = new DateTime(2000, 10, 11, 15, 32, 14);
    // Prints "2000-10-11T15:32:14"
    Console.WriteLine(dt.ToString()); 
    // Prints "Wednesday, October 11, 2000"
    Console.WriteLine("{0}", dt);     
    // Prints "10/11/2000"
    Console.WriteLine("{0:d}", dt); 
    // Prints "Wednesday, October 11, 2000"
    Console.WriteLine("{0:D}", dt); 
    // Prints "Wednesday, October 11, 2000 3:32 PM"
    Console.WriteLine("{0:f}", dt); 
    // Prints "Wednesday, October 11, 2000 3:32:14 PM"
    Console.WriteLine("{0:F}", dt); 
    // Prints "10/11/2000 3:32 PM"
    Console.WriteLine("{0:g}", dt); 
    // Prints "10/11/2000 3:32:14 PM"
    Console.WriteLine("{0:G}", dt); 
    // Prints "October 11"
    Console.WriteLine("{0:m}", dt); 
    // Prints "October 11"
    Console.WriteLine("{0:M}", dt); 
    // Prints "Wed, 11 Oct 2000 22:32:14 GMT"
    Console.WriteLine("{0:r}", dt); 
    // Prints "Wed, 11 Oct 2000 22:32:14 GMT"
    Console.WriteLine("{0:R}", dt); 
    // Prints "3:32 PM"
    Console.WriteLine("{0:t}", dt); 
    // Prints "3:32:14 PM"
    Console.WriteLine("{0:T}", dt); 
    // Prints "2000-10-11 22:32:14Z"
    Console.WriteLine("{0:u}", dt); 
    // Prints "Wednesday, October 11, 2000 10:32:14 PM"
    Console.WriteLine("{0:U}", dt); 
    // Prints "October, 2000"
    Console.WriteLine("{0:y}", dt); 
    // Prints "October, 2000"
    Console.WriteLine("{0:Y}", dt); 
    // Prints "Wednesday the 11 day of October in the year 2000"
    Console.WriteLine(
      "{0:dddd 'the' d 'day of' MMMM 'in the year' yyyy}", dt);
  }
}

Using nmake


REF=/r:c.dll
DEBUG=/debug
.SUFFIXES: .exe .dll .cs
.cs.dll:
 csc /t:module $*.cs
.cs.exe:
 csc $(DEBUG) $(REF) @<<big.tmp
$*.cs $(SRCLIST)
<<
all : d.exe f.exe
d.exe : d.cs c.dll
c.dll : a.dll b.dll
 al /out:c.dll a.dll b.dll
b.dll : b.cs
a.dll : a.cs
key.snk :
 sn -k $*.snk
e.dll : a.dll b.dll key.snk
 al /out:$*.dll /keyfile:key.snk a.dll b.dll
 al /i:$*.dll
f.exe : f.cs e.dll
 csc $(DEBUG) /r:.\e.dll f.cs
clean:
 del a.dll b.dll c.dll d.exe /q




C# MSN Bot – The beginnings.

Following on from my C# IRC bot that I wrote a few months ago, I thought I’d share some of my work with the MSN protocol. This is a little bit more complicated than the IRC protocol in that it requires hashing and authentification using HTTPS. Excellent generic documentation for implementing the MSN protocol which can be used with pretty much any programming language can be found here.
Pretty much the main purpose of this code right now is to control the notification server and authenticate the client with a few methods there for future use, which is the main server where statuses and other such things are written. It isn’t the best written code but it should be a good example of how the connection method using MSN works and how it can be implemented in the C# language. Any feedback is welcome via comment, but there is more to come and probably a lot more cleanup to be done (much of the stuff in dispatch_server method is reused in notification_server method for example). Throwing error messages can also be improved, but I hope it is useful to someone.
Controlling chat connections and the switchboard will be dealt with in further blogs on this.
Code below:
    /* Implementing MSN Protocol 8 in C# (Notification Server)
     * by Gareth Peoples
     * mail[at]gpeopl.es / gareth.peoples.2009[at]nuim.ie
     * Blog at www.gpeopl.es
     *
     * See http://msnpiki.msnfanatic.com/index.php/MSNP8:Example_Session
     * for protocol information.
     */


using System;
using System.IO;
using System.Net;
using System.Web;
using System.Text;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace msnprotocol
{
    public class MSN    {
        int count = 1; // Count to record the current step in the transaction
        String username = ""; // String to record the username
        String password = ""; // String to record the password
        TcpClient socket; // Initialising socket variable
        StreamWriter writer; // Initialising a writer instance
        StreamReader reader; // Initialising a reader instance
       
        /* Constructor to load username and password in from an
         * external C# class that wishes to use this work */

        public MSN (String username, String password) {
            this.username = username;
            this.password = password;
            String[] notification = dispatch_server("messenger.hotmail.com", 1863);
            notification_server(notification[0], Convert.ToInt32(notification[1]));
        }
       
        /* Method to connect to the dispatch server with set host and
         * port information to be provided by an external class that wishes
         * to use our basic MSNP8 library */

        public String[] dispatch_server(String host, int port) {
            String data = "";
            String[] splitData;
            String[] notificationData;
            try {
                socket = new TcpClient(host, port); // Open connection
                socket.ReceiveBufferSize = 1024;
                Console.WriteLine("Successfully connected to dispatch server");
                NetworkStream stream = socket.GetStream(); // getting stream for connection
                reader = new StreamReader(stream); // setting up reader to read from stream
                writer = new StreamWriter(stream); // setting up writer to write to stream
                write("VER " + count + " MSNP8 CVR0"); // Write the first data string to the server
                // Reading and interpreting data given by the dispatch server
                try {
                    while(true) {
                        data = reader.ReadLine(); // Read a line of data from stream
                        Console.WriteLine("< << " + data); // Write server responses to console
                        splitData = data.Split(' '); // Split data up for interpretation
                        if (splitData[0].Equals("VER")) {
                            write("CVR " + count + " 0x0409 win 4.10 i386 MSNMSGR 5.0.544 MSNMSGS " + username);
                        }
                        else if (splitData[0].Equals("CVR")) {
                            write("USR " + count + " TWN I " + username);
                        }
                       
                        // Transfer to a different server
                        else if (splitData[0].Equals("XFR") && !splitData[2].Equals("SB")) {
                            notificationData = splitData[3].Split(':');
                            reader.Close();
                            writer.Close();
                            stream.Close();
                            return notificationData; // returns notification data for the server
                        }
                    }
                }
                catch {
                    Console.WriteLine("Stopped reading from dispatch server");
                }  
            }
            catch {
                Console.WriteLine("Error: Unable to connect to server");
            }
            return null; // if the code crashes return nothing
        }
       
        /* Method to connect to the notification server with set host and
         * port information to be provided by an external class that wishes
         * to use our basic MSNP8 library */

        public void notification_server(String host, int port) {
            String data;
            String[] splitData;
            String authdata;
            try {
                // Create a new socket
                socket = new TcpClient(host, port);
                // Set the buffer size
                socket.ReceiveBufferSize = 1024;
                Console.WriteLine("Connected to notification server");
                NetworkStream stream = socket.GetStream();
                reader = new StreamReader(stream);
                writer = new StreamWriter(stream);
                write("VER " + count + " MSNP8 CVR0");
                    while(true) {
                        data = reader.ReadLine();
                            splitData = data.Split(' ');
                            Console.WriteLine("<<< " + data);
                            // Send server information about the system
                            if (splitData[0].Equals("VER")) {
                                write("CVR " + count + " 0x0409 win 4.10 i386 MSNMSGR 5.0.544 MSNMSGS " + username);
                            }
                            // Request authentification
                            else if (splitData[0].Equals("CVR")) {
                                write("USR " + count + " TWN I " + username);
                            }
                            // If the server is ready for authentification do this using HTTPS methods
                            else if (splitData[0].Equals("USR") && splitData[2].Equals("TWN")) {
                                authdata = splitData[4];
                                authentification(authdata);
                            }
                            // If the server has finished logging in
                            else if(splitData[0].Equals("ClientPort:")) {
                                Console.WriteLine("Successfully logged in");
                                // Request information about contacts
                                write("SYN " + count + " 0");
                                // Set online status
                                write("CHG " + count + " NLN");
                            }
                            // If a challenge is received
                            else if(splitData[0].Equals("CHL")) {
                                challenge(splitData[2]);
                            }
                            // If a contact's status is received
                            else if(splitData[0].Equals("ILN")) {
                            }
                    }
            }
            catch {
                Console.WriteLine("Connection to notification server closed");
            }
        }
       
        /* Tweener MSN Passport authentification method using HTTPS takes place here
         * using data from the notification server */

        public void authentification(String auth) {
            String working = "";
            String ticket = "";
            String connecturl = "";
            String authoriseheader = "";
            String[] split;
            try {
                Console.WriteLine("Connecting to nexus server");
                // Send all certificate validation requests to Validator method
                ServicePointManager.ServerCertificateValidationCallback = Validator;
                // Address for nexus server
                String address = "https://nexus.passport.com/rdr/pprdr.asp";
                // Set up web request
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
                // Set up web response
                HttpWebResponse response = (HttpWebResponse) request.GetResponse();
                // Get the passport URL's header for redirecting to login server
                working = response.GetResponseHeader("PassportURLs");
                split = working.Split(',');
                split = split[1].Split('=');
                connecturl = split[1];
                response.Close();
                /* Connect to login server provided by nexus server to get official
                 * log in ticket */

                try {
                    Console.WriteLine("Connecting to login server: https://" + connecturl);
                    // Set up web request for
                    request = (HttpWebRequest)WebRequest.Create("https://" + connecturl);
                    // Set up a header for authentification by server
                    authoriseheader = "Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,";
                    authoriseheader += "sign-in=" + urlencode(username) + ",pwd=" + urlencode(password) + "," + auth;
                    request.Headers.Add("Authorization", authoriseheader);
                    response = (HttpWebResponse) request.GetResponse();
                    working = response.GetResponseHeader("Authentication-Info");
                    split = working.Split(',');
                    ticket = split[1].Substring(9);
                    ticket = ticket.TrimEnd('\'');
                    write("USR " + count + " TWN S " + ticket);
                }
                catch  {
                    Console.WriteLine("Error: Unable to connect to login server https://" + connecturl);
                }
            }
            catch {
                Console.WriteLine("Error: Unable to connect to nexus server");
            }
        }
        /* Avoiding SSL validation errors
         * See http://www.mono-project.com/UsingTrustedRootsRespectfully for more information */

       
        public static bool Validator(object sender, X509Certificate certificate,
                                     X509Chain chain, SslPolicyErrors sslPolicyErrors) {
            return true;
        }
       
        /* Method for writing to the network stream */
        public void write(String data) {
            try {
                writer.WriteLine(data); // Write data to network stream
                Console.WriteLine(">>> " + data); // Show this on console
                writer.Flush();
                count++;
            }
            catch {
                Console.WriteLine("Error: in writing line to server");
            }
        }
       
        /* Method for sending challenge to MSN notification server */
        public void challenge(String data) {
            try {
                data += "I2EBK%PYNLZL5_J4";
                byte[] array = Encoding.Default.GetBytes(data);
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                array = md5.ComputeHash(array);
                data = "";
                foreach (byte a in array) {
                    if (a < 16) data += "0" + a.ToString("x");
                    else data += a.ToString("x");
                }
                write("QRY " + count + " PROD00504RLUG%WL " + data.Length);
                Console.WriteLine("Sent hash: " + data);
                writer.Write(data);
                writer.Flush();
            }
            catch {
                Console.WriteLine("Unable to compute and send challenge hash");
            }
        }
       
        /* Method for dealing with setting status on the MSN notification server */
        public void setStatus(String status) {
            if (status.Equals("online")) {
                Console.WriteLine("Changing status to online...");
                write("CHG " + count + " NLN 0");
            }
            else if (status.Equals("away")) {
                Console.WriteLine("Changing status to away...");
                write("CHG " + count + " AWY 0");
            }
            else if (status.Equals("busy")) {
                Console.WriteLine("Changing status to busy...");
                write("CHG " + count + " BSY 0");
            }
            else if (status.Equals("lunch")) {
                Console.WriteLine("Changing status to out to lunch...");
                write("CHG " + count + " LUN 0");
            }
            else if (status.Equals("idle")) {
                Console.WriteLine("Setting status to idle...");
                write("CHG " + count + " IDL 0");
            }
            else if (status.Equals("phone")) {
                Console.WriteLine("Changing status to on the phone...");
                write("CHG " + count + " PHN 0");
            }
            else if (status.Equals("hidden")) {
                Console.WriteLine("Changing status to appear offline...");
                write("CHG " + count + " HDN 0");
            }
            else {
                Console.WriteLine("Incorrect: must be away, busy, idle or online");
            }
        }
       
        /* Method for setting new nickname on the MSN notification server */
        public void setNickname(String nick) {
            Console.WriteLine("Changing your nick name to " + nick);
            write("REA " + count + " " + passport + " " + urlencode(nick));
        }
       
        /* Method for terminating connection to MSN notification server */
        public void close() {
            Console.WriteLine("Closing connection...");
            write("OUT");
        }
       
        // Method for handling url encoding (upper case)
        public String urlencode(String data) {
            data = HttpUtility.UrlEncode(data);
            char[] current = data.ToCharArray();
            // Converting lower case characters to upper case
            for (int i = 0; i < data.Length; i++) {
                if (current[i].Equals('%')) {
                    current[i+1] = Char.ToUpper(current[i+1]);
                    current[i+2] = Char.ToUpper(current[i+2]);
                }
            }
            data = new String(current);
            return data;
        }
       
        // Method for blocking users
        public void blockUser(String passport) {
            Console.WriteLine("Blocking user with passport: " + passport);
            // Remove user with passport from allow list
            write("REM " + count + " AL " + passport);
            // Move user with passport to block list
            write("ADD " + count + " BL " + passport);
        }
       
        // Method for adding users
        public void addUser(String passport) {
            Console.WriteLine("Adding user with passport: " + passport);
            // Place user on allow list
            write("ADD " + count + " AL " + passport + " " + passport);
        }
       
    }
}