C# Tips & Tricks

  • When normalizing strings, it is highly recommended that you use ToUpperInvariant instead of ToLowerInvariant because Microsoft has optimized the code for doing uppercase comparisons.

    Reference Book: (CLR via C#, Second Edition (Developer Reference)).

  • Don't use ToUpper () to do a comparison of a case sensitive string.

    When you "convert a string to upper case" you create a second temporary string object. So, use:
    String.Equals(stringA, stringB, StringComparison.CurrentCultureIgnoreCase)

  • Converting to uppercase rather than lowercase can also prevent incorrect behavior in certain cultures. For example, in Turkish, two lowercase i's map to the same uppercase I. Google "Turkish i" for more details.

    I (English) – Ben (Turkish)
    I (English) – I (Turkish)

  • Null coalescing operator

    It is a binary operator that is the part of basic conditional expression. In C# the null Coalescing operator is ?.

    Example:
    1. string pageTitle = suppliedTitle ?? "Default Title";  
  • My favorite trick is using the null coalesce operator and parentheses to automatically instantiate collections for me.

    Example

    1. private IList<Foo> _foo;  
    2. public IList<Foo> ListOfFoo  

    3.    get

    4.    {
    5.        return _foo ?? (_foo = new List<Foo>());
    6.    }
    7. }  
  • MyClass myObject = (MyClass) obj; Vs MyClass myObject = obj as MyClass;

    The second will return null if obj isn't a MyClass, rather than throw a class InvalidCastException exception.

  • You can collapse your code down even further:
    1. Employee emp = new Employee();  
    2. emp.Name = "John Smith";  
    3. emp.StartDate = DateTime.Now(); 
    Now, use:
    1. Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}  
  • The "default" keyword in generic types:
    1. T t = default(T); 
    Results in a "null" if T is a reference type and 0 if it is an int, false if it is a Boolean and so on.

  • Verbatim string

    A String can be created as a verbatim string. Verbatim strings start with the @ symbol. The C# compiler understand this type of string as verbatim. Basically the @ symbol tells the string constructor to ignore escape characters and line breaks.

    Example

    String Str1 = "";
    Str1 = "\\MyServer\TestFolder\NewFolder";

    In the statement above, the compiler gives an error of "Unrecognized escape sequence", but if we write the code like this:

    str2 = @"\\MyServer\TestFolder\NewFolder";

  • Using @ for variable names that are keywords.

    var @object = new object();
    var @string = "";
    var @if = IpsoFacto();

  • Extension Method

    Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.

    The most common extension methods are the LINQ standard query operators that add query functionality to the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable<T> types.

    Example
    1. class ExtensionMethods2  
    2. {  
    3.    static void Main()  
    4.    {  
    5.       int[] ints = { 10, 45, 15, 39, 21, 26 };  
    6.       var result = ints.OrderBy(g => g);  
    7.       foreach (var i in result)  
    8.       {  
    9.          System.Console.Write(i + " ");  
    10.       }  
    11.    }  
    12. }  
    13.   
    14. //Output: 10 15 21 26 39 45  
  • Anonymous types can infer property names from the variable name:
    1. string hello = "world";  
    2. var o = new { hello };  
    3. Console.WriteLine(o.hello); 

  • Dictionary.TryGetValue(K key, out V value):
    1. if(dictionary.ContainsKey(key))  
    2. {  
    3.    value = dictionary[key];  

    You can just do:
    1. if(dictionary.TryGetValue(key, out value))  
    2. { ... } 
    Another benefit of TryGetValue is that if your dictionary is synchronized, there is no race condition.

  • Use "throw;" instead of "throw ex;" to preserve stack trace

    If re-throw an exception without adding additional information, use "throw" instead of "throw ex". An empty "throw" statement in a catch block will emit a specific IL that re-throws the exception while preserving the original stack trace. "throw ex" loses the stack trace to the original source of the exception.

  • Object.Equals Method

    For instance, when you want to compare two objects for equality, not knowing if they're null. How many times did you write something like that?
    1. if ((x == y) || ((x != null && y != null) && x.Equals(y)))  
    2. {  
    3. ...  

    It can be implemented like the following in one line of code:
    1. if (Object.Equals(x, y))  
    2. { }   
  • Falling through switch-cases can be done by having no code in a case:
    1. switch (/*...*/)
    2. {  
    3.    Case 0: // shares the exact same code as case 1  
    4.    Case 1:  
    5.    // do something  
    6.    Goto case 2;  
    7.    Case 2:  
    8.    // do something else  
    9.    Goto default;  
    10.    default:  
    11.    // do something entirely different  
    12.    break;  
    13. }  
  • Nested classes can access private members of an outer class.

  • To test if an IEnumerable<T> is empty with LINQ, use:

    IEnumerable<T>.Any();

    • At first, I was using (IEnumerable<T>.Count() != 0) ...
    • That unnecessarily causes all items in the IEnumerable<T> to be enumerated.
    • As an improvement to this, I went on to use (IEnumerable<T>.FirstOrDefault() == null) ...
    • Which is better.
    • But IEnumerable<T>.Any() is the most succinct and performs the best.

  • Trailing Comments

    Trialing comments are generally written on the same line as code with some tabs to separate them. These are short comments generally used to add information about variables, object declarations and so on.

    Example
    1. long controlcounts; // Count of the controls in current context  
  • Assignment and Type Check
    1. class A {...}  
    2. class B : A {...}  
    3. class C: B {...} 
    Assignments
    1. A a = new A();// static type of a: the type specified in the declaration (here A)  
    2. // dynamic type of a: the type of the object in a (here also A)  
    3. a = new B();// dynamic type of a is B  
    4. a = new C();// dynamic type of a is C  
    5. B b = a; // forbidden; compilation error 
    Run time type checks
    1. a = new C();  
    2. if (a is C) ...// true, if dynamic type of a is C or a subclass; otherwise false  
    3. if (a is B) ...// true  
    4. if (a is A) ...// true, but warning because it makes no sense  
    5. a = null;  
    6. if (a is C) ...// false: if a== null, a is T always returns false  
  • Cast
    1. A a = new C();  
    2. a = null;  
    3. c = (C) a;// ok ..null can be casted to any reference type 
    Properties and indexers can also be overridden (virtual, override).

  • Dynamic Binding
    1. class A  
    2. {  
    3.    public virtualvoid WhoAreYou()  
    4.    {
    5.       Console.WriteLine("I am an A");  
    6.    }  

    Now:
    1. class B : A  
    2. {  
    3.    public overridevoid WhoAreYou()  
    4.    {
    5.       Console.WriteLine("I am a B"); 
    6.    } 
    7. }
    Now:
    1. A a = new B();a.WhoAreYou();// "I am a B"
  • Hiding

    Members can be declared as “new” in subclass.
    They hide inherited members with the same class.
    1. class A  
    2. {  
    3.    public int x;  
    4.    public void F() {...}  
    5.    public virtual void G() {...}  

    Now:
    1. class B : A  
    2. {  
    3.    public newint x;  
    4.    public new void F() {...}  
    5.    public newvoid G() {...}  

    Now:
    1. B b = new B();  
    2. b.x = ...;// // accesses B.x  
    3. b.F(); …. b.G(); // CallsB.F and B.G
  • Dynamic Binding (with Hiding)
    1. class A
    2. {  
    3.    public virtualvoid WhoAreYou() { Console.WriteLine("I am an A"); }  
    4. }  
    5. class B : A
    6. {  
    7.    public overridevoid WhoAreYou() { Console.WriteLine("I am a B"); }  
    8. }  
    9. class C : B
    10. {  
    11.    public new virtualvoid WhoAreYou() { Console.WriteLine("I am a C"); }  
    12. }  
    13. class D : C
    14. {  
    15.    public overridevoid WhoAreYou() { Console.WriteLine("I am a D"); }  

    Now:
    1. C c = new D();  
    2. c.WhoAreYou();// "I am a D"  
    3. A a = new D();  
    4. a.WhoAreYou();// "I am a B" !!