All notes
LanguageReferenc

TODO

Classes (C# Programming Guide)
Structs (C# Programming Guide)
Namespaces (C# Programming Guide)
Interfaces (C# Programming Guide)
Delegates (C# Programming Guide)

General

Anonymous Functions

Lambda expression

A lambda expression is an anonymous function that you can use to create delegates or expression tree types, particularly helpful for writing LINQ query expressions. By using lambda expressions, you can write local functions that can be passed as arguments or returned as the value of function calls.

The => operator has the same precedence as assignment (=) and is right associative.

Expression Lambdas

Expression lambdas are used extensively in the construction of Expression Trees.


// The parentheses are optional only if the lambda has one input parameter
(input parameters) => expression
(x, y) => x == y

// Sometimes it is difficult or impossible for the compiler to infer the input types. When this occurs, specify the types explicitly:
(int x, string s) => s.Length > x

// Specify zero input parameters with empty parentheses:
// wcfNote: Not recommended, violating anonymity?
() => SomeMethod()

Statement Lambdas


// Resembles an expression lambda except that the statement(s) is enclosed in braces:
(input parameters) => {statement;}

delegate void TestDelegate(string s);
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");

Statement lambdas, like anonymous methods, cannot be used to create expression trees.

Async Lambdas


public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        // ExampleMethodAsync returns a Task.
        await ExampleMethodAsync();
        textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

// You can add the same event handler by using an async lambda. To add this handler, add an async modifier before the lambda parameter list:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += async (sender, e) =>
        {
            // ExampleMethodAsync returns a Task.
            await ExampleMethodAsync();
            textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
        };
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

Anonymous Methods

MSDN.

C# 2.0 introduced anonymous methods and in C# 3.0 and later, lambda expressions supersede anonymous methods as the preferred way to write inline code.

There is one case in which an anonymous method provides functionality not found in lambda expressions. Anonymous methods enable you to omit the parameter list. This means that an anonymous method can be converted to delegates with a variety of signatures. This is not possible with lambda expressions.


// Two examples:

// Create a handler for a click event.
button1.Click += delegate(System.Object o, System.EventArgs e)
                   { System.Windows.Forms.MessageBox.Show("Click!"); };

// Create a delegate.
delegate void Del(int x);
// Instantiate the delegate using an anonymous method.
Del d = delegate(int k) { /* ... */ };

outer variables of the anonymous method. For example, in the following code segment, n is an outer variable:


int n = 0;
Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n); };

A reference to the outer variable n is said to be captured when the delegate is created. Unlike local variables, the lifetime of a captured variable extends until the delegates that reference the anonymous methods are eligible for garbage collection.

Datatypes

Collections.Generic

Containers.

List

C# program that initializes string list:



using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
	    // Use collection initializer.
	    List<string> list1 = new List<string>()
	    {
	        "carrot",
	        "fox",
	        "explorer"
	    };
        
	    // Use var keyword with collection initializer.
	    var list2 = new List<string>()
	    {
	        "carrot",
	        "fox",
	        "explorer"
	    };
        
	    // Use new array as parameter.
	    string[] array = { "carrot", "fox", "explorer" };
	    List<string> list3 = new List<string>(array);
        
	    // Use capacity in constructor and assign.
	    List<string> list4 = new List<string>(3);
	    list4.Add(null); // Add empty references. (BAD)
	    list4.Add(null);
	    list4.Add(null);
	    list4[0] = "carrot"; // Assign those references.
	    list4[1] = "fox";
	    list4[2] = "explorer";
        
	    // Use Add method for each element.
	    List<string> list5 = new List<string>();
	    list5.Add("carrot");
	    list5.Add("fox");
	    list5.Add("explorer");
        
	    // Make sure they all have the same number of elements.
	    Console.WriteLine(list1.Count);
	    Console.WriteLine(list2.Count);
	    Console.WriteLine(list3.Count);
	    Console.WriteLine(list4.Count);
	    Console.WriteLine(list5.Count);
    }
}

// Output
// 
// 3
// 3
// 3
// 3
// 3

Dictionary

MSDN: Dictionary.

Retrieving a value by using its key is very fast, close to O(1), because the Dictionary<TKey, TValue> class is implemented as a hash table.

A key cannot be null, but a value can be, if the value type TValue is a reference type.


using System;
using System.Collections.Generic;

public class Example
{
    public static void Main()
    {
        Dictionary<string, string> openWith = new Dictionary<string, string>();

        // Add some elements to the dictionary. There are no duplicate keys, but some of the values are duplicates.
        openWith.Add("txt", "notepad.exe");
        openWith.Add("bmp", "paint.exe");
        openWith.Add("dib", "paint.exe");
        openWith.Add("rtf", "wordpad.exe");

        // The Add method throws an exception if the new key is already in the dictionary.
        try
        {
            openWith.Add("txt", "winword.exe");
        }
        catch (ArgumentException)
        {
            Console.WriteLine("An element with Key = \"txt\" already exists.");
        }

        // The Item property is another name for the indexer, so you can omit its name when accessing elements. 
        Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);

        // The indexer can be used to change the value associated with a key.
        openWith["rtf"] = "winword.exe";
        Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);

        // If a key does not exist, setting the indexer for that key adds a new key/value pair.
        openWith["doc"] = "winword.exe";

        // The indexer throws an exception if the requested key is not in the dictionary.
        try
        {
            Console.WriteLine("For key = \"tif\", value = {0}.", openWith["tif"]);
        }
        catch (KeyNotFoundException)
        {
            Console.WriteLine("Key = \"tif\" is not found.");
        }

        // When a program often has to try keys that turn out not to be in the dictionary, TryGetValue can be a more efficient way to retrieve values.
        string value = "";
        if (openWith.TryGetValue("tif", out value))
        {
            Console.WriteLine("For key = \"tif\", value = {0}.", value);
        }
        else
        {
            Console.WriteLine("Key = \"tif\" is not found.");
        }

        // ContainsKey can be used to test keys before inserting them.
        if (!openWith.ContainsKey("ht"))
        {
            openWith.Add("ht", "hypertrm.exe");
            Console.WriteLine("Value added for key = \"ht\": {0}", openWith["ht"]);
        }

        // When you use foreach to enumerate dictionary elements, the elements are retrieved as KeyValuePair objects.
        Console.WriteLine();
        foreach( KeyValuePair<string, string> kvp in openWith )
        {
            Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
        }

        // To get the values alone, use the Values property.
        Dictionary<string, string>.ValueCollection valueColl = openWith.Values;

        // The elements of the ValueCollection are strongly typed with the type that was specified for dictionary values.
        Console.WriteLine();
        foreach( string s in valueColl )
        {
            Console.WriteLine("Value = {0}", s);
        }

        // To get the keys alone, use the Keys property.
        Dictionary<string, string>.KeyCollection keyColl = openWith.Keys;

        // The elements of the KeyCollection are strongly typed with the type that was specified for dictionary keys.
        Console.WriteLine();
        foreach( string s in keyColl )
        {
            Console.WriteLine("Key = {0}", s);
        }

        // Use the Remove method to remove a key/value pair.
        Console.WriteLine("\nRemove(\"doc\")");
        openWith.Remove("doc");
        if (!openWith.ContainsKey("doc"))
        {
            Console.WriteLine("Key \"doc\" is not found.");
        }
    }
}

/* This code example produces the following output:

An element with Key = "txt" already exists.
For key = "rtf", value = wordpad.exe.
For key = "rtf", value = winword.exe.
Key = "tif" is not found.
Key = "tif" is not found.
Value added for key = "ht": hypertrm.exe

Key = txt, Value = notepad.exe
Key = bmp, Value = paint.exe
Key = dib, Value = paint.exe
Key = rtf, Value = winword.exe
Key = doc, Value = winword.exe
Key = ht, Value = hypertrm.exe

Value = notepad.exe
Value = paint.exe
Value = paint.exe
Value = winword.exe
Value = winword.exe
Value = hypertrm.exe

Key = txt
Key = bmp
Key = dib
Key = rtf
Key = doc
Key = ht

Remove("doc")
Key "doc" is not found.
 */

Integers

SO. Convert long to int:


int MyInt = (int) ( MyLong & 0xFFFFFFFF )

string

string is an alias for String in the .NET Framework.

Although string is a reference type, the equality operators (== and !=) are defined to compare the values of string objects, not references. This makes testing for string equality more intuitive.


// Lower.
string aStr = "Hello";
Console.WriteLine(aStr.ToLower());

// int to string

int varInt = 1;
string varString = Convert.ToString(varInt);
string varString2 = varInt.ToString();

// string to int

string str = string.Empty;
str = "123";
int result=int.Parse(str);
// TryParse() returns true if succeed, otherwise false.
int.TryParse(str, out result);

// @-quoted.

string a = @"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"

// To include a double quotation mark in an @-quoted string, double it:
string a = @"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.

// Environment.NewLine. A newline on Windows equals \r\n.
var line = "This is a line" + Environment.NewLine;

// Format
string s = String.Format("At {0}, the temperature is {1}°C.", DateTime.Now, 20.4);
// Output similar to: 'At 4/10/2015 9:29:41 AM, the temperature is 20.4°C.'

// Positive values add padding to the left, negative add padding to the right
// Sample                                 Generates
String.Format("[{0, 10}]", "Foo");  //   [∙∙∙∙∙∙∙Foo]
String.Format("[{0, 5}]", "Foo");   //   [∙∙Foo]
String.Format("[{0, -5}]", "Foo");  //   [Foo∙∙]
String.Format("[{0, -10}]", "Foo"); //   [Foo∙∙∙∙∙∙∙]

// Replace spaces with a empty string.
xyz.Replace(" ", string.empty);

Remove duplicates from string list


// Use a HashSet:
a = new HashSet<string>(a).ToArray();

// Use a LINQ query:
// You can use an IEqualityComparer as a parameter, such as .Distinct(StringComparer.OrdinalIgnoreCase) to get a case-insensitive distinct set of strings.
int[] s = { 1, 2, 3, 3, 4};
int[] q = s.Distinct().ToArray();

Modify a string

Because strings are immutable, it is not possible (without using unsafe code) to modify the value of a string object after it has been created. However, there are many ways to modify the value of a string and store the result in a new string object.

MSDN: modify string contents.


class ReplaceSubstrings
{
    string searchFor;
    string replaceWith;

    static void Main(string[] args)
    {

        ReplaceSubstrings app = new ReplaceSubstrings();
        string s = "The mountains are behind the clouds today.";

        // Replace one substring with another with String.Replace.
        // Only exact matches are supported.
        s = s.Replace("mountains", "peaks");
        Console.WriteLine(s);
        // Output: The peaks are behind the clouds today.

        // Use Regex.Replace for more flexibility. 
        // Replace "the" or "The" with "many" or "Many".
        // using System.Text.RegularExpressions
        app.searchFor = "the"; // A very simple regular expression.
        app.replaceWith = "many";
        s = Regex.Replace(s, app.searchFor, app.ReplaceMatchCase, RegexOptions.IgnoreCase);
        Console.WriteLine(s);
        // Output: Many peaks are behind many clouds today.

        // Replace all occurrences of one char with another.
        s = s.Replace(' ', '_');
        Console.WriteLine(s);
        // Output: Many_peaks_are_behind_many_clouds_today.

        // Remove a substring from the middle of the string.
        string temp = "many_";
        int i = s.IndexOf(temp);
        if (i >= 0)
        {
            s = s.Remove(i, temp.Length);
        }
        Console.WriteLine(s);
        // Output: Many_peaks_are_behind_clouds_today.

        // Remove trailing and leading whitespace.
        // See also the TrimStart and TrimEnd methods.
        string s2 = "    I'm wider than I need to be.      ";
        // Store the results in a new string variable.
        temp = s2.Trim();
        Console.WriteLine(temp);
        // Output: I'm wider than I need to be.
    }

    // Custom match method called by Regex.Replace
    // using System.Text.RegularExpressions
    string ReplaceMatchCase(Match m)
    {
        // Test whether the match is capitalized
        if (Char.IsUpper(m.Value[0]) == true)
        {
            // Capitalize the replacement string
            // using System.Text;
            StringBuilder sb = new StringBuilder(replaceWith);
            sb[0] = (Char.ToUpper(sb[0]));
            return sb.ToString();
        }
        else
        {
            return replaceWith;
        }
    }
}

class ModifyStrings
{
    static void Main()
    {
        string str = "The quick brown fox jumped over the fence";
        System.Console.WriteLine(str);

        char[] chars = str.ToCharArray();
        int animalIndex = str.IndexOf("fox");
        if (animalIndex != -1)
        {
            chars[animalIndex++] = 'c';
            chars[animalIndex++] = 'a';
            chars[animalIndex] = 't';
        }

        string str2 = new string(chars);
        System.Console.WriteLine(str2);

        // Keep the console window open in debug mode
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}
/* Output:
  The quick brown fox jumped over the fence
  The quick brown cat jumped over the fence 
*/

It demonstrates one possible side effect of unsafe operations on strings that results from the way that the C# compiler stores (interns) strings internally. In general, you should not use this technique unless it is absolutely necessary.


class UnsafeString
{
    unsafe static void Main(string[] args)
    {
        // Compiler will store (intern) 
        // these strings in same location.
        string s1 = "Hello";
        string s2 = "Hello";

        // Change one string using unsafe code.
        fixed (char* p = s1)
        {
            p[0] = 'C';
        }

        //  Both strings have changed.
        Console.WriteLine(s1);
        Console.WriteLine(s2);

        // Keep console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}

Arrays

The following examples create:


class TestArraysClass
{
    static void Main()
    {
        // Declare a single-dimensional array 
        int[] array1 = new int[5];
        // Declare and set array element values
        int[] array2 = new int[] { 1, 3, 5, 7, 9 };
        // Alternative syntax
        int[] array3 = { 1, 2, 3, 4, 5, 6 };

        // Declare a two dimensional array
        int[,] multiDimensionalArray1 = new int[2, 3];
        // Declare and set array element values
        int[,] multiDimensionalArray2 = { { 1, 2, 3 }, { 4, 5, 6 } };

        // Declare a jagged array
        int[][] jaggedArray = new int[6][];
        // Set the values of the first array in the jagged array structure
        jaggedArray[0] = new int[4] { 1, 2, 3, 4 };
    }
}

Methods

Sort

wcfNote: As in JS and PHP, Upper case must precede lowercase, such as: "1" "D" "d". To achieve this, always use .Sort(StringComparer.Ordinal). See SO.


using System;
using System.Collections.Generic;

class IntroToLINQ
{
    static void Main()
    {
        var strList = new List<string>{"d", "D", "1"};

        strList.Sort();
        foreach (var i in strList)
        {
            Console.WriteLine(i);
        }

        strList.Sort(StringComparer.Ordinal);
        foreach (var i in strList)
        {
            Console.WriteLine(i);
        }
    }
}

// 1
// d
// D
// 
// 1
// D
// d

Anonymous Types

wcfNote: instances of anonymous type are read-only!


//POST数据例子:{ "expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": { "scene": { "scene_id": 123} } }
// Anonymous Type is read-only.
var postData = new { expire_seconds = 604800, action_name = "QR_SCENE", action_info = new { scene = new { scene_id = sceneID } } };

var data = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(postData));

Enum

String to enum

SO: how to convert a string to an enum.


public static T ToEnum<T>(this string value, T defaultValue) where T : struct, IComparable
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    T result;
    // true: ignoreCase is true.
    return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

// Which enables the call:
StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);

SO: generics error that the type T must be a non-nullable type. If we don't specify where T : struct, a compiler error "type T must be a non-nullable type" will be thrown.

Classes and Structs

A class is a reference type, while a struct is a value type.

In C#, there are no global variables or methods as there are in some other languages. All of them, even a program's entry point, the Main method, must be declared within a class or struct.

Classes (but not structs) can be declared as static. A static class can contain only static members and cannot be instantiated with the new keyword. One copy of the class is loaded into memory when the program loads.

Constructors

Both classes and structs can define constructors that take parameters.

Constructors that take parameters must be called through a new statement or a base statement.

Static constructors are called automatically, immediately before any static fields are accessed, and are generally used to initialize static class members.


// Public Constructor:
public class Taxi
{
    public bool isInitialized;
    public Taxi()
    {
        isInitialized = true;
    }
}

class TestTaxi
{
    static void Main()
    {
        Taxi t = new Taxi();
        Console.WriteLine(t.isInitialized);
    }
}

// Private Constructor:
class NLog
{
    private NLog() { }

    public static double e = Math.E;  //2.71828...
}

// Call Constructor by Base()
public class Manager : Employee
{
    public Manager(int annualSalary)
        : base(annualSalary)
    {
        //Add further instructions here.
    }
}

public class Employee
{
    public int salary;

    // Con1
    public Employee(int annualSalary)
    {
        salary = annualSalary;
    }

    // Con2
    public Employee(int weeklySalary, int numberOfWeeks)
    {
        salary = weeklySalary * numberOfWeeks;
    }

    // Another version of Con2
    // Call a constructor from another constructor:
    // It use "this" to call Con1
    public Employee(int weeklySalary, int numberOfWeeks)
        : this(weeklySalary * numberOfWeeks)
    {
    }
}

Struct constructors

Structs cannot contain an explicit default constructor because one is provided automatically by the compiler. This constructor initializes each field in the struct to the default values. However, this default constructor is only invoked if the struct is instantiated with new().


int i = new int();
Console.WriteLine(i);

// Compile Error:
// because it tries to use an object that has not been initialized.
int i;
Console.WriteLine(i);

// The following are ok:
int a = 44;  // Initialize the value type...
int b;
b = 33;      // Or assign it before using it.
Console.WriteLine("{0}, {1}", a, b);

Destructors

Properties

Properties enable a class to expose a public way of getting and setting values, while hiding implementation or verification code.

The value keyword is used to define the value being assigned by the set accessor.

Properties that do not implement a set accessor are read only.


class TimePeriod
{
    private double seconds;

    public double Hours
    {
        get { return seconds / 3600; }
        set { seconds = value * 3600; }
    }
}

class Program
{
    static void Main()
    {
        TimePeriod t = new TimePeriod();

        // Assigning the Hours property causes the 'set' accessor to be called.
        t.Hours = 24;

        // Evaluating the Hours property causes the 'get' accessor to be called.
        System.Console.WriteLine("Time in hours: " + t.Hours);
    }
}

Properties that simply return immediately with the result of an expression:



public string Name => First + " " + Last; 

Auto-Implemented Properties

MSDN: Auto-Implemented Properties (C# Programming Guide).

Auto-implemented properties make property-declaration more concise when no additional logic is required in the property accessors. The compiler creates a private, anonymous backing field that can only be accessed through the property's get and set accessors.


// In C# 3.0 and later
// Auto-Impl Properties for trivial get and set
public double TotalPurchases { get; set; }
public string Name { get; set; }
public int CustomerID { get; set; }

// In C# 6 and later
public string FirstName { get; set; } = "Jane";

Immutable lightweight class. Use it instead of a struct when you must use reference type semantics.

You can make an immutable property in two ways.

You can declare the set accessor.to be private. The property is only settable within the type, but it is immutable to consumers. You can instead declare only the get accessor, which makes the property immutable everywhere except in the type’s constructor.

When you declare a private set accessor, you cannot use an object initializer to initialize the property. You must use a constructor or a factory method.

Methods

Extension Methods


namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' },
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
}

// The WordCount extension method can be brought into scope with this using directive:
using ExtensionMethods;

// And it can be called from an application by using this syntax:
string s = "Hello Extension Methods";
int i = s.WordCount();

Classes FAQ

How to choose between struct and class

The general rule to follow is that structs should be small, simple (one-level) collections of related properties, that are immutable once created; for anything else, use a class. SO.

MSDN: choosing between classes and structures.

Reference types are allocated on the heap, and memory management is handled by the garbage collector. Value types are allocated on the stack or inline and are deallocated when they go out of scope. In general, value types are cheaper to allocate and deallocate. However, if they are used in scenarios that require a significant amount of boxing and unboxing, they perform poorly as compared to reference types.

Why to avoid mutable struct

SO. Structs are value types which means they are copied when they are passed around. So if you change a copy you are changing only that copy, not the original and not any other copies which might be around. If your struct is immutable then all automatic copies resulting from being passed by value will be the same. If you want to change it you have to consciously do it by creating a new instance of the struct with the modified data. (not a copy).

SO: when do you use a struct instead of a class.

If you were to have a reference type as a member of your struct (not disallowed, but extremely bad practice in virtually all cases); the class would not be cloned (only the struct's reference to it), so changes to the struct would not affect the original object, but changes to the struct's subclass WILL affect the instance from the calling code. This can very easily put mutable structs in very inconsistent states that can cause errors a long way away from where the real problem is.

For this reason, virtually every authority on C# says to always make your structures immutable; allow the consumer to specify the properties' values only on construction of an object, and never provide any means to change that instance's values. Readonly fields, or get-only properties, are the rule.

If the consumer wants to change the value, they can create a new object based on the values of the old one, with the changes they want, or they can call a method which will do the same. This forces them to treat a single instance of your struct as one conceptual "value", indivisible and distinct from (but possibly equatable to) all others. If they perform an operation on a "value" stored by your type, they get a new "value" which is different from their initial value, but still comparable and/or semantically equatable.

For a good example, look at the DateTime type. You cannot assign any of the fields of a DateTime instance directly; you must either create a new one, or call a method on the existing one which will produce a new instance. This is because a date and time are a "value", like the number 5, and a change to the number 5 results in a new value that is not 5. Just because 5+1 = 6 doesn't mean 5 is now 6 because you added 1 to it. DateTimes work the same way; 12:00 does not "become" 12:01 if you add a minute, you instead get a new value 12:01 that is distinct from 12:00. If this is a logical state of affairs for your type (good conceptual examples that aren't built in to .NET are Money, Distance, Weight, and other quantities of a UOM where operations must take all parts of the value into account), then use a struct and design it accordingly. In most other cases where the sub-items of an object should be independently mutable, use a class.

The Difference Between Passing a Struct and Passing a Class Reference to a Method

MSDN.

A struct is a value type, when you pass a struct by value to a method, the method receives and operates on a copy of the struct argument.

A class instance is a reference type, not a value type. When a reference type is passed by value to a method, the method receives a copy of the reference to the class instance.

How to print all properties of an object

StackOverflow.


using System.ComponentModel;
foreach(PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj))
{
    string name=descriptor.Name;
    object value=descriptor.GetValue(obj);
    Console.WriteLine("{0}={1}",name,value);
}

// Or
using System.Web.Script.Serialization;
// Converts an object to a JSON string.
public string Serialize(object obj);

Keywords

using

using statement

wcfNote: the variable used in using clause should inherit from IDisposal.

You can achieve the same result with a try-finally block; in fact, this is how the using statement is translated by the compiler.

Note the extra curly braces to create the limited scope for the object:


{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

This is not a best practice: the object remains in scope after control leaves the using block even though it will probably no longer have access to its unmanaged resources. In other words, it will no longer be fully initialized. If you try to use the object outside the using block, you risk causing an exception to be thrown.


////// Bad practice:

Font font2 = new Font("Arial", 10.0f);
using (font2) // not recommended
{
    // use font2
}
// font2 is still in scope
// but the method call throws an exception
float f = font2.GetHeight();

// Good:
using (Font font3 = new Font("Arial", 10.0f),
            font4 = new Font("Arial", 10.0f))
{
    // Use font3 and font4.
}

using Directive: Equivalent of Typedef

SO: equivalent of typedef in c#.

No, there's no equivalent of typedef. You can use using directives within one file, e.g. (but that will only impact that source file.)


using CustomerList = System.Collections.Generic.List<Customer>;

Operator Keywords

as

as operator is used to perform certain types of conversions between compatible reference types or nullable types.

The as operator is like a cast operation. However, if the conversion isn't possible, as returns null instead of raising an exception.

expression as type is equivalent to the following expression except that the expression variable is evaluated only one time: expression is type ? (type)expression : (type)null.

The as operator performs only reference conversions, nullable conversions, and boxing conversions. The as operator can't perform other conversions, such as user-defined conversions, which should instead be performed by using cast expressions.


class csrefKeywordsOperators
{
    class Base
    {
        public override string  ToString()
        {
           return "Base";
        }
    }
    class Derived : Base 
    { }

    class Program
    {
        static void Main()
        {
            Derived d = new Derived();

            Base b = d as Base;
            if (b != null)
            {
                Console.WriteLine(b.ToString()); // Output: Base
            }
        }
    }
}

class ClassA { }
class ClassB { }

class MainClass
{
    static void Main()
    {
        object[] objArray = new object[6];
        objArray[0] = new ClassA();
        objArray[1] = new ClassB();
        objArray[2] = "hello";
        objArray[3] = 123;
        objArray[4] = 123.4;
        objArray[5] = null;

        for (int i = 0; i < objArray.Length; ++i)
        {
            string s = objArray[i] as string;
            Console.Write("{0}:", i);
            if (s != null)
            {
                Console.WriteLine("'" + s + "'");
            }
            else
            {
                Console.WriteLine("not a string");
            }
        }
    }
}
/*
Output:
0:not a string
1:not a string
2:'hello'
3:not a string
4:not a string
5:not a string
*/

Don't do this:


// Bad code - checks type twice for no reason
if (randomObject is TargetType)
{
    TargetType foo = (TargetType) randomObject;
    // Do something with foo
}

is

MSDN.

Checks if an object is compatible with a given type.

The is operator cannot be overloaded.

Anonymous methods are not allowed on the left side of the is operator. This exception includes lambda expressions.


static void Test(object o)
{
    Class1 a;
    Class2 b;

    if (o is Class1)
    {
        Console.WriteLine("o is Class1");
        a = (Class1)o;
    }
    else if (o is Class2)
    {
        Console.WriteLine("o is Class2");
        b = (Class2)o;
    }
    else
    {
        Console.WriteLine("o is neither Class1 nor Class2.");
    }
}

Parameter Keywords

ref

If you want the called method to change the value of the parameter, you must pass it by reference, using the ref or out keyword.

Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by ref regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference.


class PassingValByRef
{
    static void SquareIt(ref int x)
    // The parameter x is passed by reference.
    // Changes to x will affect the original value of x.
    {
        x *= x;
        System.Console.WriteLine("The value inside the method: {0}", x);
    }
    static void Main()
    {
        int n = 5;
        System.Console.WriteLine("The value before calling the method: {0}", n);

        SquareIt(ref n);  // Passing the variable by reference.
        System.Console.WriteLine("The value after calling the method: {0}", n);

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}
/* Output:
    The value before calling the method: 5
    The value inside the method: 25
    The value after calling the method: 25
*/

Members of a class can't have signatures that differ only by ref and out.

However, overloading can be done when one method has a ref or out parameter and the other has a value parameter.


class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}

class RefOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(ref int i) { }
}

Properties are not variables. They are methods, and cannot be passed to ref parameters.

Compare to out

An argument that is passed to a ref parameter must be initialized before it is passed. This differs from out parameters, whose arguments do not have to be explicitly initialized before they are passed.

Operators

??

MSDN.


class NullCoalesce
{
    static int? GetNullableInt()
    {
        return null;
    }

    static string GetStringValue()
    {
        return null;
    }

    static void Main()
    {
        int? x = null;

        // Set y to the value of x if x is NOT null; otherwise,
        // if x = null, set y to -1.
        int y = x ?? -1;

        // Assign i to return value of the method if the method's result
        // is NOT null; otherwise, if the result is null, set i to the
        // default value of int.
        int i = GetNullableInt() ?? default(int);

        string s = GetStringValue();
        // Display the value of s if s is NOT null; otherwise, 
        // display the string "Unspecified".
        Console.WriteLine(s ?? "Unspecified");
    }
}

Nullable, int?

MSDN: Nullable Types.

The syntax T? is shorthand for Nullable<T>, where T is a value type. The two forms are interchangeable. Assign a value to a nullable type just as you would for an ordinary value type, for example int? x = 10; or double? d = 4.108. A nullable type can also be assigned the value null: int? x = null.

Syntax

Switch, case


int caseSwitch = 1;
switch (caseSwitch)
{
    case 1:
        Console.WriteLine("Case 1");
        break;
    case 2:
        Console.WriteLine("Case 2");
        break;
    default:
        Console.WriteLine("Default case");
        break;
}

Try, Catch, Finally

Try-catch

MSDN: try-catch (C# Reference).

You can use a predicate expression that further examines the exception to decide whether to handle it. If the predicate expression returns false, then the search for a handler continues.

Exception filters are preferable to catching and rethrowing (explained below) because filters leave the stack unharmed. If a later handler dumps the stack, you can see where the exception originally came from, rather than just the last place it was rethrown.

A common use of exception filter expressions is logging. You can create a predicate function that always returns false that also outputs to a log, you can log exceptions as they go by without having to handle them and rethrow.


catch (ArgumentException e) when (e.ParamName == "...")
{
}

Try-finally

MSDN: try-finally (C# Reference).

By using a finally block, you can clean up any resources that are allocated in a try block, and you can run code even if an exception occurs in the try block. Typically, the statements of a finally block run when control leaves a try statement.

Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. One solution is to add a catch block to the try-finally statement.

Concepts

Boxing and Unboxing

Boxing is the process of converting a value type to the type object or to any interface type implemented by this value type. When the CLR boxes a value type, it wraps the value inside a System.Object and stores it on the managed heap. Unboxing extracts the value type from the object.

Boxing is implicit; unboxing is explicit. The concept of boxing and unboxing underlies the C# unified view of the type system in which a value of any type can be treated as an object.


int i = 123;
// The following line boxes i.
object o = i;
o = 123;
i = (int)o;  // unboxing

For the unboxing of value types to succeed at run time, the item being unboxed must be a reference to an object that was previously created by boxing an instance of that value type. Attempting to unbox null causes a NullReferenceException. Attempting to unbox a reference to an incompatible value type causes an InvalidCastException.

Even unboxing an int value to short cause an InvalidCastException. See below.


class TestUnboxing
{
    static void Main()
    {
        int i = 123;
        object o = i;  // implicit boxing

        try
        {
            int j = (short)o;  // attempt to unbox

            System.Console.WriteLine("Unboxing OK.");
        }
        catch (System.InvalidCastException e)
        {
            System.Console.WriteLine("{0} Error: Incorrect unboxing.", e.Message);
        }
    }
}

Performance

In relation to simple assignments, boxing and unboxing are computationally expensive processes. When a value type is boxed, a new object must be allocated and constructed. To a lesser degree, the cast required for unboxing is also expensive computationally.

Reflection

An assembly is a reusable, versionable, and self-describing building block of a common language runtime application.

Reflection provides objects (of type System.Type) that describe assemblies, modules and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, reflection enables you to access them.


// Using "GetType" to obtain type information:
int i = 42;
System.Type type = i.GetType();
System.Console.WriteLine(type);
// Output: System.Int32

// Using Reflection to get information from an Assembly:
System.Reflection.Assembly info = typeof(System.Int32).Assembly;
System.Console.WriteLine(info);
// Output:
// mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

// create instance of class DateTime
DateTime dateTime = (DateTime)Activator.CreateInstance(typeof(DateTime));

// create instance of DateTime, use constructor with parameters (year, month, day)
DateTime dateTime = (DateTime)Activator.CreateInstance(typeof(DateTime), new object[] { 2008, 7, 4 });

// File A.
namespace Test
{
    public class Calculator
    {
        public Calculator() { ... }
        private double _number;
        public double Number { get { ... } set { ... } }
        public void Clear() { ... }
        private void DoClear() { ... }
        public double Add(double number) { ... }
        public static double Pi { ... }
        public static double GetPi() { ... }
    }
}
// Now file A is compiled to be Test.dll.

// dynamically load assembly from file Test.dll
Assembly testAssembly = Assembly.LoadFile(@"c:\Test.dll");

// get type of class Calculator from just loaded assembly
Type calcType = testAssembly.GetType("Test.Calculator");

// create instance of class Calculator
object calcInstance = Activator.CreateInstance(calcType);

// get info about property: public double Number
PropertyInfo numberPropertyInfo = calcType.GetProperty("Number");
double value = (double)numberPropertyInfo.GetValue(calcInstance, null);
numberPropertyInfo.SetValue(calcInstance, 10.0, null);

// get info about static property: public static double Pi
PropertyInfo piPropertyInfo = calcType.GetProperty("Pi");
double piValue = (double)piPropertyInfo.GetValue(null, null);

// invoke public instance method
calcType.InvokeMember("Clear", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, calcInstance, null);

// invoke private instance method
calcType.InvokeMember("DoClear", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, null, calcInstance, null);

// invoke public instance method
double value = (double)calcType.InvokeMember("Add", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, calcInstance, new object[] { 20.0 });

// invoke public static method: public static double GetPi()
double piValue = (double)calcType.InvokeMember("GetPi", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, null);

// get value of private field: private double _number
double value = (double)calcType.InvokeMember("_number", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic, null, calcInstance, null);

Activator

SO.


Object createObjectBy(Type clazz){
   // .. do construction work here
    Object theObject = Activator.CreateInstance(clazz);
    return theObject;
}

// If Type is known at design time:
public static T CreateInstance<T>() where T: new()
{
    // Do some business logic
    Logger.LogObjectCreation(typeof(T));

    // Actualy instanciate the object
    return new T();
}

If you only need to create your object once, just stick with the Activator.CreateInstance method. If you need to create it multiple time in a short time, try the lambda approach. That last approach is similar to a compiled regular expression vs. an on-the-fly regular expression.

Reference and Value type

Passing reference as parameters

A variable of a reference type does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data pointed to by the reference, such as the value of a class member. However, you cannot change the value of the reference itself; that is, you cannot use the same reference to allocate memory for a new class and have it persist outside the block. To do that, pass the parameter using the ref or out keyword.


class PassingRefByVal 
{
    static void Change(int[] pArray)
    {
        pArray[0] = 888;  // This change affects the original element.
        pArray = new int[5] {-3, -1, -2, -3, -4};   // This change is local.
        System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
    }

    static void Main() 
    {
        int[] arr = {1, 4, 5};
        System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]);

        // A copy of the reference, which points to arr, is passed to the method.
        Change(arr);
        System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
    }
}
/* Output:
    Inside Main, before calling the method, the first element is: 1
    Inside the method, the first element is: -3
    Inside Main, after calling the method, the first element is: 888
*/

class PassingRefByRef 
{
    static void Change(ref int[] pArray)
    {
        // Both of the following changes will affect the original variables:
        pArray[0] = 888;
        pArray = new int[5] {-3, -1, -2, -3, -4};
        System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
    }

    static void Main() 
    {
        int[] arr = {1, 4, 5};
        System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);

        Change(ref arr);
        System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
    }
}
/* Output:
    Inside Main, before calling the method, the first element is: 1
    Inside the method, the first element is: -3
    Inside Main, after calling the method, the first element is: -3
*/

FAQ

Equivalent of typedef

SO: equivalent-of-typedef-in-c-sharp.


using CustomerList = System.Collections.Generic.List<Customer>;