Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How does it work in C#? - Part 2

0.00/5 (No votes)
4 Feb 2013 1  
How does throw, rethrow and where, select clause of Enumerable class work in C# programming language.

Contents

  • Introduction
  • How does it work?
    • throw an exceptionObject
    • Where and Select of Enumerable
  • Limitations
  • History
  • Reference

Source code and demo

Introduction

In the first part of How does it work in C#? article I discussed about the var, auto-implemented properties and += and -= of events in C#. In this article, I will be discussing about throwing an exception and how does it work and what is the internal mechanism for these, what is internal working mechanism of where and select clause of Enumerable class in C#.

How does it work?

In the following discussion we will see the internal working mechanism about the throw statement and where, select of Enumerable class.

throw an exceptionObject

Exception is one of the common scenarios for any application. As a result, proper exception management is one of the important tasks in application development. In here, I would like to discuss about throw statement in C#, how does throw anExceptionObject; or just throw works. I wrote a small program which will help me to explain the details. The task of this program is simple, it will raise an exception and throw it,

namespace TestHarnessPart2
{
    using System;
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Person person = new Person();
            }
            catch (Exception exceptionObject)
            {
                throw;
            }
        }
    }
    public class Person
    {
        public Person()
        {
            throw new Exception("Exception from Person.");
        }
    }
}

The above code catch the exception and just throw it with out passing any explicit exception object.I created another version of this above code for example,

namespace TestHarnessPart2
{
    using System;
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Person person = new Person();
            }
            catch (Exception exceptionObject)
            {
                throw exceptionObject;
            }
        }
    }
    public class Person
    {
        public Person()
        {
            throw new Exception("Exception from Person.");
        }
    }
}

The above code will create a Person object and if any exception occurred during this creation it will catch that exception and from the catch block it throws the catched exception which is throw exceptionObject;. Now if we see the stack trace of those above code we will find out there is difference, stack trace for first version of the code is as below,

HowitworksCSharpTwo/StackTraceThrow.PNG

Fig: Stack trace of the first version of the code.

And stack trace of the second version of the code,

HowitworksCSharpTwo/StackTraceThrowException.PNG

Fig: Stack trace of the second version of the code

From the above two images we can see the details of the stack trace is different.Now the question is how does it happens, to get the answer we will get help of ILDasm program, grab the exe of TestHarnessPart2 from the bin folder and drop into the ILDasm program , for the first version of the code we will see something like below,

HowitworksCSharpTwo/ILThrow.PNG

Fig :IL code for using just throw in the catch block.

From the above image we can see exceptionObject has been defined as local variable using .locals init [1] but in the catch block compiler change the throw statement into

catch [mscorlib]System.Exception 
{
   IL_000b:  stloc.1
   IL_000c:  nop
   IL_000d:  rethrow
}  // end handler

rethrow, which means compiler does not change the original stack trace of the exception object it is re- throwing the existing one, where as if we look into the following image for the second version of the above C# code,

HowitworksCSharpTwo/ILThrowExceptionObject.PNG

Fig: IL code for using just throw excetpionObject in the catch block.

We can see exceptionObject has been defined as local variable as well, using the same way for the first version of the code for example, .locals init [1]. But in the catch block it is doing totally different stuffs compare to first version of the above code. In the catch block compiler load location of 1( ldloc.1) which is the exceptionObject

  catch [mscorlib]System.Exception
  {
    IL_000b:  stloc.1
    IL_000c:  nop
    IL_000d:  ldloc.1
    IL_000e:  throw
  }  // end handler

and throw that one. As a result, this exceptionObject will not hold all the stack trace raised earlier except the stack trace from this current state. Now the last bit of the puzzle is, what actually throw and rethrow statement does? From the Partition III CIL.doc retrieved from ECMA C# and Common Language Infrastructure Standards we can see what actually throw and rethrow does,

IL Instruction Description
throw Throw an exception. The throw instruction throws the exception object (type O) on the stack and empties the stack. So in relation to the second version of the code block it will be,
[1] class [mscorlib]System.Exception 
exceptionObject
rethrow Rethrow the current exception. The rethrow instruction is only permitted within the body of a catch handler. It throws the same exception that was caught by this handler. A rethrow does not change the stack trace in the object.

So it is clear that throw exceptionObject override the stack trace where as, just throw statement does not override the stack trace.

Where and Select of Enumerable

Before we start discussing about Where and Select, just have a quick look of the where and select clause’s signature,

HowitworksCSharpTwo/WhereSignature.PNG

Fig: Signature of the Where clause

HowitworksCSharpTwo/SelectSignature.PNG

Fig: Signature of the Select clause

Where and Select is two extension methods of Enumerable class in .Net. Following sections will discuss about the internal of Where and Select, how does it work. Before, we go ahead just bit of heads up about Func in .Net. According to MSDN, we can use this delegate to represent a method that can be passed as a parameter without explicitly declaring a custom delegate. The encapsulated method must correspond to the method signature that is defined by this delegate. A simple example of Func below,

namespace TestHarnessPart2
{
    using System;
    public class ExampleOfFunc
    {
        public int TestFunc(string dataToCheck, Func<string,> getLength)
        {
            return getLength(dataToCheck);
        }
    }
}

and to test the above code,

private static void TestFuncExample()
{
    ExampleOfFunc exampleOfFunc = new ExampleOfFunc();
    Console.WriteLine(exampleOfFunc.TestFunc("Example of Func", (dataToTest) => dataToTest.Length));
}

So from the above code we can see TestFunc method accepting a Func as parameter and execute it just by doing return getLength(dataToCheck);, from the caller of this method is actually passing an anonymous method block for the Func parameter. Through out the entire discussion about where and select we will find this concept used many places,

Before we go ahead I like to show a bit of code created to explain the where and select statement,

namespace TestHarnessPart2
{
    using System.Collections.Generic;
    using System.Linq;
    class WhereSelect
    {
        List<string> bookList = new List<string>() { "Einstein: His Life and Universe", "Ideas And Opinions", "The World As I See It " };
        public IEnumerable<string> GetBookListWhichLengthIsGreaterThan(int lengthOfTheBookName)
        {
            //return bookList.Where(book => book.Length == lengthOfTheBookName).Select(book => book);
            return bookList.Where(book =>
            {
                var currentBook = book;
                return book.Length > lengthOfTheBookName;
            }).Select(book =>
            {
                var currentBook = book;
                return book;
            });
        }
    }
}

The above code is not doing much rather check the booklist whether it has book which name length is greater than given length (lengthOfTheBookName). Now we will try to find out bit of internal working mechanism of Where and Select clause, where and select clause is defined in the Enumerable class and internal of the where clause is as below,

HowitworksCSharpTwo/WhereInternal.PNG
Fig: Where internal

From the above image we see Where method is calling another internal private class named WhereListIterator<T> which is doing all the work for us which is filter the booklist List based on the condition provided and return output.

private class WhereListIterator<tsource> : Enumerable.Iterator<tsource>
{
      public override bool MoveNext()
      {
        // most of the code has been removed for simplicity
        while (this.enumerator.MoveNext())
        {
          TSource current = this.enumerator.Current;
          if (this.predicate(current))
          {
            base.current = current;
            return true;
          }
        }
      }
}

From the above code we can see this.predicate(current)) line of code is actually executing the Func or anonymous method block in this case, <GetBookListWhichLengthIsGreaterThan>b__0 method. On the other hand, select clause is working like below,

HowitworksCSharpTwo/SelectInternal.PNG

Fig: Select internal

Also, from the above image we can see that there is one selector which is actually <GetBookListWhichLengthIsGreaterThan>b__1 method to select the item from the list. Now need to find out where is this <GetBookListWhichLengthIsGreaterThan>b__1 and

<GetBookListWhichLengthIsGreaterThan>b__0
coming from? Please have a look image below, from the following image we can there is two method named <GetBookListWhichLengthIsGreaterThan>b__1 used for selector and
<GetBookListWhichLengthIsGreaterThan>b__0 used for predicate of the where clause.

HowitworksCSharpTwo/OutputOfTheWhereSelectWithPredicates.PNG

Fig: The output of WhereSelect test

Where and Select clause is using those two methods for doing the operation. Bit of more investigation to find out about it. Now we need the help of .Net Reflector and ILDasm. First grab the TestHarnessPart2.exe from the bin folder and drop into .Net Reflector, then we will find out following interesting stuff, a class <>c__DisplayClass3 with following details,

[CompilerGenerated]
private sealed class <>c__DisplayClass3
{
    // Fields
    public int lengthOfTheBookName;
    // Methods
    public bool <GetBookListWhichLengthIsGreaterThan><getbooklistwhichlengthisgreaterthan>b__0(string book)
    {
        string currentBook = book;
        return (book.Length > this.lengthOfTheBookName);
    }
}

From the class we can see a method named <GetBookListWhichLengthIsGreaterThan>b__0 which is actually containing the filtering condition we defined in the where clause,

{
     var currentBook = book;
     return book.Length > lengthOfTheBookName;
}

And also there is also another method (outside of <>c__DisplayClass3 class) named <GetBookListWhichLengthIsGreaterThan>b__1

[CompilerGenerated]
private static string <GetbookListWhichLengthIsGreaterThan><getbooklistwhichlengthisgreaterthan>b__1(string book)
{
    string CS$<>8__locals4 = book;
    return book;
}

Which is actually containing the statement we defined for the select clause as below,

{
     var currentBook = book;
     return book;
}

Now to prove the above stuff, we will look at the IL code retrieved from ILDasm(also grab the TestHarnessPart2.exe from the bin folder and drop into ILDasm program) for the above C# code,

HowitworksCSharpTwo/ILCodeForWhereSelect.PNG

Fig: IL code of the GetBookListWhichLengthIsGreaterThan method

From the above image we can see where clause is using <GetBookListWhichLengthIsGreaterThan>b__0 method of <>c__DisplayClass3 class and select clause is using <GetBookListWhichLengthIsGreaterThan>b__1 method. So it is clear now how does it work.

Limitation

  • There are no discussions about Query Expression and Lambda Expression.

History

  • Version 1

Reference

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here