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