C# and .NET Secrets - Quiz
13 October 2009 - .NET
We invite you to prove your knowledge about certain subjects concerning Microsoft .NET technology by participating in a monthly quiz. This month the quiz is about C# and .NET secrets. In this article you can reread the questions. Additionally you get background information about the correct answers.
Here is a list of all questions included in the quiz. Use the hyperlinks to jump to the topic you are interested in:
- Question 1 - A Simple One To Start
- Question 2 - String vs. System.String
- Question 3 - Implicitly Typed Variables
- Question 4 - Value vs. Reference Types
- Question 5 - Finalizing Objects
- Question 6 - Lambda Expressions
- Question 7 - Nullable Types
- Question 8 - JIT Compiler
The CTS (Common Type System) does not know about object orientation at all. Programming languages like C# include all the OO logic. They generate procedural IL code behind the scenes. True or false?
That's absolutely not true! The Common Type System supports object oriented and procedural languages. It has support for OO constructs built in.
If you are interested you can download the ECMA C# and Common Language Infrastructure Standards from Microsoft's website. The documents include a good introduction into as well as a detailed documentation of the Common Type System.
What is more efficient in respect of memory usage and performance: The use of string or the use of System.String?
The correct answer is It doesn’t matter which one you take, they perform equally. string is a synonym for System.String. Therefore it does not matter if you take string or System.String.
You can prove that the C# compiler and the .NET CLR treats string and System.Stringequally by looking at the generated code in intermediate language. Take a look at the following lines of code. As you can see we define two classes handling strings. One of them (PersonString) uses string to do its job; the other (PersonSystemString) usesSystem.String.
This class uses string.
Mark the use of auto-implemented properties in this sample. This is a new feature of C# 3.0!
This class uses System.String.
The implementation of Main uses implicitly typed variables. This is a new featur of C# 3.0! See question 2 for more details about implicitly typed variables.
IL code of the two classes
After compiling the program we can use ILDASM (MS Intermediate Language Disassembler) to generate a readable version of the IL:
If you compare the IL of the two classes you can see that they are (with the exception of their names) absolutely identical.
C# 3.0 introduces implicitly typed local variables. You do not need to specify a type for a local variable any more! The compiler figures out which type to use for you. So what do you think; does the following code work?
You can read more about implicitly typed local variables in MSDN.
The correct answer is No, you cannot compile this code.
The code does not compile. The line v = 10; produces the error Cannot implicitly convert type 'int' to 'string'. The reason is that the new keyword var does not meanvariant! It just means that the compiler determines and assigns the most appropriate type during compile time!
What is the output of the following program?
The correct answer is Hello World! 99.
System.String is called immutable (read-only) because its value cannot be modified once it has been created.
Although System.String is a class and therefore a reference type you can never change the content of a string. Every modification to a string variable generates a new String object. Therefore the assignment of "Hello Austria!" to stringValue does not affect the value ofstringValue2.
System.Array behaves differently. If you assign an array to another variable only a new reference to the array is generated. A modification of an array element is visible to everyone holding a reference to the array. Knowing this it should be clear to you why array2contains 99 even if this value has been assigned to array.
It is a good practise to use destructors in C# just like in C++. Put cleanup code in your class' destructor and the CLR will care for the rest. Is that correct?
The correct answer is Cleaning up in the destructor is fine. But that is not enough!
is the same as
C# knows destructors. A destructor is the same as a Finalize-Method in which you callbase.Finalize(); at the end. However, using finalizers costs performance. Additionally you have to be aware that finalizers are not called when an object is no longer needed by your program. It is called when the garbage collector decides to remove the object. Usually you cannot predict when that will happen. Therefore you have to do a little bit more to provide a proper cleanup mechanism in your programs.
Take a look at the following program:
If you run this program you will notice that the output Closing file! appears at the very end of the program. The destructor is not immediately called when the object fGen is out of scope. The CLR calls it when the garbage collector frees the object.
This is one of the reasons why a destructor or a finalizer is not enough for an object that has to clean up when it is no longer needed. Here is a list of things you should consider regarding cleanup:
Jeffrey Richter wrote an interesting article about memory management and finalization of objects in the MSDN Magazine. Although the text has been written in 2000 it is still worth reading!
- Try to avoid objects that require clean up!
- If you cannot avoid it provide a destructor or a finalizer.
- Add an additional method with which a user can
force the object to clean up.
- Implement the IDisposable interface by providing a Dispose-method. Follow the guidelines for implementing IDisposable that are included in MSDN.
- If a user can (re)open the object using some kind of Open-method offer aClose-method in addition to Dispose. The Close-method should call Disposeinternally.
- Do not forget to call SuppressFinalize in your Dispose-method. Otherwise you would waste performance.
- Objects that implement IDisposable should be used inside C# using statement. It automatically cleans up correctly.
In C# every method must have a name. True or false?
That's not true! Since the version 2.0 C# has known anonymous methods. Take a look at the following code:
The main-method creates an anonymous method that is passed in the calc-parameter to thePerformCalculation-method. This construct is quite useful in a situation when having to create a method might seem an unnecessary overhead.
Read more about Lambda Expressions in MSDN.
In C# 3.0 you can replace anonymous methods with Lamdba Expressions in most cases. In our case we could change the implementation of the Main-method as follows:
If you take a look behind the scenes and check the intermediate language that the C# compiler generates you will see that the generated IL nearly does not differ between C# 2.0 anonymous methods and Lamdba Expressions.
What is the output of the following program?
The correct answer is 20.
In C# you can make every value type nullable by adding a question mark to the type's name (you could also use System.Nullable<T> instead of the ?). The operator ?? can be used to specify a default value for an expression. This default value is returned if the expression evaluates to null. In our case c is null; therefore a + c is null and the default value b (20) is returned.
The JIT compiler converts the IL in a portable executable into native machine language...
The correct answer is method by method.
During loading the CLR creates a stub for each method in a type when it is loaded and initialized. When a method is called for the first time the stub passes control to the JIT compiler which converts the MSIL for that method into native code. If the method is called again the native code is executed without involving the JIT.
You can observe how the JITter generates native code using the following code sample:
In the Performance Monitor you can see how the JITter generates native code.
Note: You cannot use ngen with ASP.NET (for details see Microsoft Support Site).
If you do not want to convert your IL code method by method every time the program starts you can use the Native Image Generator (ngen.exe) to convert it e.g. during installation. ngen generates processor-specific machine code in the native image cache. The runtime uses these images from the cache instead of using the JIT compiler to compile the original assembly.