My Development Notes

By Haemoglobin
8/31/2010 (revision 43)

Areas

Conventions

  • Don't give type and namespace the same name [1].

Language Features

Lazy Class

public class Awesomeness
{
    private Lazy<AwesomeObject> _ourAwesomeObject = new Lazy<AwesomeObject>(() =>
    {
        var awesomeObject = new AwesomeObject();
        //do stuff here to build your awesomeObject
        return awesomeObject;
    });

    public AwesomeObject OurAwesomeObject
    {
        get { return _ourAwesomeObject.Value; }
    }
}

Tuples (4.0) and Type Inferrence (3.0)

The Tuple object in 4.0 can handle up to 8 parameters.

var data = new Tuple<string,int>(“John Doe”, 42); //can't use type inferrence with constuctors.

var data = Tuple.Create<string,int>(“John Doe”, 42);
var data = Tuple.Create(“John Doe”, 42); //same as above but using type inferrence

string name = data.Item1; 
int age = data.Item2;

"A Tuple is often used to return multiple values from functions when you don’t want to create a specific type. Although not a perfect analogy, this is somewhat similar to how one uses Anonymous Types, except that Anonymous Types cannot go outside a method boundary like a Tuple." http://www.davidhayden.me/2009/12/tuple-in-c-4-c-4-examples.html

Parallel Programming

Parallel.For (0, count, delegate int(i)
{
  //for loop body
});
//control passed here once all parallel iterations complete

Parallel.ForEach (arr, (string item) =>{
  // Do something
});

Extension Methods

  • References: 1, 2

Yield

Shortening and Widening Conversions

int i = 1; 
double d = 1.0001; 
d = i;  //implicit widening conversion. 

class MyInt : IConvertable {
    int Value; 

    //Use the following for when a cast is required to cast MyInt to int i.e (int)MyInt
    public static explicit operator int(MyInt i) {
        return i.Value; 
    }

    //Use the following for when a cast is not required to convert int to MyInt e.g MyInt i = 5; 
    public static implicit operator MyInt(int i) {
        return new MyInt(i); 
    }

    public bool IConvertable:ToBoolean(IFormatProvider provider) {
        return Convert.ToBoolean(Value);
    }
    ...
}

Convert.ToBoolean(myInt); 

Casting

The Prefix cast:

GenericType g=...;
SpecificType t=(SpecificType) g;

The as cast:

GenericType g=...;
SpecificType t=g as SpecificType;
  • Returns a null when the variable you are trying to convert is not of the requested type or in it's inheritance chain, instead of throwing an exception.
  • Using as will not perform user-defined conversions, such as implicit or explicit conversion operators, which casting syntax will do.
  • Faster.

Events / Delegates

public class MyEventArgs : EventArgs { }  //EventArgs is an empty class used for events with no data

//A Multicast delegate is a delegate returning void, and multiple instances can be chained to events with += and removed with -. 
public delegate void MyEventHandler(object sender, MyEventArgs e);
public event MyEventHandler MyEvent; //or use EventArgs&lt;MyEventArgs&gt; instead of MyEventHandler

if (MyEvent != null) { //null if there are no handlers
    MyEvent(this, new MyEventArgs());
}

MyClass.MyEvent += new MyEventHandler(MyHandleEvent); 

Action<T> and Func<TResult>

    static void Main(string[] args)
    {
        int result = DoStuffToSomething<DateTime, DateTime, int>(
            DateTime.Now, 
            DateTime.MaxValue,
            date => {
                    Console.WriteLine(date.ToShortDateString()); 
                    Console.WriteLine(date.ToLongTimeString());
                }, 
            (date1, date2) => (date2 - date1).Days);

        Console.WriteLine(result.ToString() + " days before .NET DateTime explodes."); 

        Console.Read();
    }

    static R DoStuffToSomething<T1, T2, R>(T1 something, T2 somethingElse, Action<T1> myAction, Func<T1, T2, R> myFunction)
    {
        myAction(something);
        return myFunction(something, somethingElse);
    }

Prints: 
22/04/2010
12:16:24 p.m.
2918175 days before .NET DateTime explodes.

More info:

Note there are other overloads for providing more parameters, e.g:

  • Action<T1, T2, T3>
  • Func<T1, T2, T3, TResult>

Lambda expressions

Formatting

string.Format("Price: {0}",price);
string.Format("Price: {0,5}",price); //right align
string.Format("Price: {0,-5}",price); //left align

Value Types

  • System.ValueType : System.Object

These are copied and passed around on the stack.

keywordTypeBytesRange
sbyteSystem.SByte1-128-127
byteSystem.Byte10-255
shortSystem.Int162-32768-32767
intSystem.Int324-2,147,483,648-2,147,483,647
uintSystem.UInt324
longSystem.Int648
floatSystem.Single4
doubleSystem.Double8
decimalSystem.Decimal16
charSystem.Char2
boolSystem.Boolean1
System.DateTime8

Note int and double are optimised by the .NET framework and hardware

Structs

Structs are value types (copied entirely onto stack when passed as parameter (unless the ref keyword is used) or when assigned to another - not just memory pointer)

Use structs if:

  • Instance size less than 16 bytes.
  • Not frequently changed.
  • Not cast (boxed) to a reference type.

Hint: override ToString(), Equals & GetHash in structs to prevent boxing.

Enums

public Enum Titles { Mr, Mrs, Ms, Dr } 

Reference Types

  • System.Object

Reference types are stored in the heap and are cleaned up by the garbage collector when there are no more references to the object.

GC.Collect(); //to force a garbage collection

//If a value type has been boxed into a reference type, you can find out if it is a value type by.
object o = 5; //boxing
o.GetType().IsValueType; 
int i = (int)o; //unboxing 
i.ToString(); //boxing (because the ToString() method exists on Object)
//Note that boxing and unboxing both have performance hits and should not be done in loops.

Strings are immutable (can't be changed)

Strings have operator overloads to cause value type behavior:

  • + Joins two strings to create a new string
  • == True if the string contents are the same
  • = Copies the contents of the string to the new string, called when passed as a parameter by value.

Nullable

//Note that a nullable value type is still passed around as a value type.
bool? b = null; 
//or
Nullable&lt;bool&gt; b = null; 
b.HasValue
b.Value 
if (b == null) {...}

Arrays

int[] ar = { 1, 3, 2 }; 
Array.Sort(ar); 

Exceptions

Exception
 .Message 
 .StackTrace
 .Source (library)
 .Data (user defined name/value pairs)

 throw new Exception("Exception message"); 

//For defining custom exception classes to throw. Message / Data is overridden. Simply extended Exception is now recommended however.
 ApplicationException : Exception  

Comments