What Great .NET Developers Ought To Know – Part 3


The next part will contain answers to the section called “Senior Developers/Architects“.

== What’s wrong with a line like this? DateTime.Parse(myString); ==

This line of code assumes that the myString contains a string conforming to the date time format for the current culture. It may turn out however that the string is in a different format, which may result either in a wrong result or an exception. In order to avoid such issues we should rather first determine the culture and then provide the proper System.IFormatProvider.

In order to avoid exceptions we could use DateTime.TryParse instead.

== What are PDBs? Where must they be located for debugging to work? ==

PDBs are Program DataBase files. Each binary has got its PDB created if the option in C# compiler is turned on.

A .NET PDB contains the following:

  • the source file names and their lines
  • the local variable names.

.NET PDBs differ much from native PDBs in that the latter contain a lot more information, which in case of .NET PDBs is not necessary as the required data is already available in the .NET metadata in the .NET binary file.

In order for debugging to work the PDB files should be located in a specific location. The debugger will look for the PDB files in the following order (until it finds them):

  1. The directory from which the binary was loaded
  2. The hard-coded build directory embedded in the Debug Directories in the binary file (in its PE header).
  3. (if Symbol Server is configured on the machine) Symbol Server cache directory
  4. (if Symbol Server is configured on the machine) Symbol Server

If the binary file is abc.dll, the debugger will attempt to load the abc.pdb file additionally identified by the GUID read from the binary file (abc.dll). If the GUIDs in the pdb and the binary do not match the debugger will ignore the pdb file.

== What is cyclomatic complexity and why is it important? ==

Cyclomatic complexity is a code metric that measures the amount of decision logic in a given function. The higher the number the more complex the function is and the harder it will be to test the function.

It is important to measure it in order to identify parts of code that may contain or lead to programming errors and should get refactored and/or thoroughly tested.

By convention the upper limit is 10, but it may vary from project to project and in some cases value of 15 is still acceptable.

== Write a standard lock() plus “double check” to create a critical section around a variable access ==

if (!isLocked)
{
  lock (thisObject)
  {
    if (!isLocked)
    {
	  isLocked = true;
    }
  }
}

== What is FullTrust? Do GAC’ed assemblies have FullTrust? ==

FullTrust is a security setting on .NET assemblies. If an assembly has FullTrust then it can do whatever the user under which the assembly is running can do. All GAC’ed assemblies by default are granted FullTrust.

== What benefit does your code receive if you decorate it with attributes demanding specific Security permissions? ==

If you use attributes on classes or methods to check for specific security permissions then you do not need to explicitly include the checks in the method body. Additionally you are able to more conveniently identify code that requires specific permissions.

== What does this do? gacutil /l | find /i “Corillian” ==

The command will list all the contents of the GAC and the filter those lines that contain “Corillian”, effectively showing all Corillian assemblies in GAC.

== What ports must be open for DCOM over a firewall? What is the purpose of Port 135? ==

DCOM (Distributed Component Object Model) is a technology that allows COM components to work over a network. Each COM process needs a separate port to communicate. Therefore, in the firewall, a range of ports has to be allowed for DCOM communication. The initial communication happens over a fixed port 135. After the connection is established a separate port is chosen for further communication. The purpose of port 135 is establishing a connection and getting info about the designated port number on which the communication will be continued.

== Contrast OOP and SOA. What are tenets of each? ==

OOP is Object-Oriented Programming which is a programming paradigm. In OOP we model objects that have properties and methods. They also have state. They communicate in the same process.

SOA is Service-Oriented Architecture. It defines the structure in which processes communicate over a network. Each process communicates using predefined contracts.

== How does the XmlSerializer work? What ACL permissions does a process using it require? == 

XmlSerializer uses Reflection to serialize .NET objects for storage or transport. While serializing and deserializing it can also use predefined XML Schemas.

In order to use XmlSerializer, no special ACL (Access Control List) permissions are required.

== Why is catch(Exception) almost always a bad idea? ==

If it specified a concrete exception type then it might be OK in certain scenarios. However it catches ANY exception and the only thing we know at this point is that an exception was thrown… we have no further info on it, though. In that case, in order not to swallow the exception and let higher layers of code handle it we would have to rethrow it (throw;). The proper way of using catch is to be specific about the types of exceptions we want to handle and log such exception.

== What is the difference between Debug.Write and Trace.Write? When should each be used? ==

Debug.Write is intended for logging information about the states of objects and performed actions – the logs are useful while debugging the application.

Trace.Write is intended for observing the execution of the application.

Debug.* is effective if the flag DEBUG is enabled during the build.

Trace.* is effective if the flag TRACE is enabled during the build.

Currently a better solution is using a designated logger such as NLog, etc. It allows for changing the log level in a separate configuration file anytime after deployment.

== What is the difference between a Debug and Release build? Is there a significant speed difference? Why or why not? ==

In a Release build, the code is optimized for speed and performance, which may result in removing code nesting (by inlining methods), removing loops if the compiler decides it will be more efficient, generally modifying the code execution if it leads to exactly same results, but faster.

In a Debug build, the code is compiled as is (no optimization is performed), so that it is easier to debug.

Are Release versions faster than Debug versions? It depends. They may be significantly faster and in some other cases not significantly faster.

Btw, in both cases generation of PDB files should be enabled.

== Does JITting occur per-assembly or per-method? How does this affect the working set? ==

JITting occurs per method. As a result the working set (the collection of pages in virtual pages that have recently been referenced) is extended only as much as needed.

== Contrast the use of an abstract base class against an interface? ==

An .NET abstract base class can contain method implementations while a .NET interface does not provide implementation. In .NET inheritance can be done only from a single class. A class however can implement multiple interfaces.

== What is the difference between a.Equals(b) and a == b? ==

The “==” operator is an identity operator, which means that it will return true if the objects are exactly same in case of reference types or if their values are same in case of value types. A special case is the String type that is a reference type, but during compilation “==” is treated as a value comparison.

The “Equals” method is intended to compare the contents of the objects, which means that even if the object references are not same, the method will return true if their contents match.

== In the context of a comparison, what is object identity versus object equivalence? ==

Object identity = two objects are considered to be the same if their addresses are same

Object equivalence = two objects are considered to be the same if their contents (all their fields) are same

== How would one do a deep copy in .NET? ==

Option 1: implement a Clone method on each object and handle creation of the deep copied object in the method.

Option 2: serialize the object and then deserialize it to a new object

== Explain current thinking around IClonable ==

The ICloneable.Clone does not enforce the type of cloning (shallow copy or deep copy) to be performed. Therefore according to the official MSDN docs it is not advised to be used in public APIs.

== What is boxing? ==

Boxing is a process of converting a value type into object type. Value types are stored on stack, however in .NET any value can be treated as an object that can later be stored in the managed heap. Boxing is implicit, while unboxing needs to be explicit. Boxing is an expensive operation as it involves instantiating an object in the heap, saving the reference on the stack and copying the value to the referenced object.

More can be found in the MSDN docs.

== Is string a value type or a reference type? ==

String is a reference type. It can be null and value types cannot be null.

== Why are out parameters a bad idea in .NET? Are they? ==

It depends. They have some good use cases, for example in Dictionary<TKey, TValue>.TryGetValue etc.  In which case you know that if the method returned true then you can use the returned value. Pretty useful pattern.

I would not use multiple out arguments, though. In that case, I would return just a single struct or class through the out argument or just return it from the method.

General recommendation from Microsoft: avoid it. They mention, though, that methods starting with “Try” are fine. I think so, too 😉

== Can attributes be placed on specific parameters to a method? Why is this useful? ==

They can be. An example of a useful case is the MVC BindAttribute that specifies which properties to bind in the input model.

Leave a Reply

Your email address will not be published.