Sunday, 19 May 2013

C# -Optional arguments and named arguments and a Caution while using interfaces with optional arguments

.Net Framework 4 came with  new feature of Optional arguments and Named parameters. First I will tell in brief what these features are before I go to their use in interface which i want to highlight.

In fact it is not .NET 4 but C# 4.0 has come with this feature, that's why while using visual studio 2010 this feature can be used with .NET framework 3.5, 3.0 and even 2.0.

Named Arguments:
Starting from .Net 4 we can specify method parameter specifying their name explicitly, this helps in increasing readability of code as well as the consumer of method does not need to remember the sequence of parameters.

look at the below method (in C#)

Following are all the cases in which we can call it using named arguments:

Using named arguments we can pass arguments in any order. Or we can pass parameter as positional followed by named arguments. Just note that named arguments cannot be followed by positional arguments and also while mixing positional and named arguments we cannot alter the sequence. We have to pass positional arguments as per their position. Look at the code above and look at the last two calls (call 4 and call 5) in call 4 we are not passing the positional argument in correct order. While in call 5 the named argument is followed by positional argument which is not allowed, Both of these method calls will generate compile time error.

Optional Arguments

The second related feature introduced in .Net 4 is Optional Arguments, Now we can specify default value of an argument for a method.While calling that method we have a freedom if we want to pass that parameter or just take advantage of default parameter.

Look at the below method to see how to define default value of optional arguments i have modified the GetBonus method to provide multiplier 2 as default value.

Now when calling this method we can pass this parameter or we may leave it. Look below how I have called this method.

This is a great feature which help us to avoid some of overloaded methods. At first look it seems that compiler has generated overloads for us to handle this situation but that is not the case.
Lets see how does the IL looks when i try to open the assembly using ILDASM and look at the compiled code of Main class.

This IL code clearly shows that the compiler has picked the default values where we have not provided the values for optional arguments and embedded that into the calling code. So we need to take precaution when we are just trying to change the default value in the class defining the method containing optional arguments and replace this assembly only and not recompiling the assembly of callable code. In that case the old default values will be used as that will still be present embedded in callable code.

Remember named arguments can be used to solve a situation in which we want to skip one of the argument in between and want to pass the later. look at the example below
What if I want to pass yearsOfService but do not want to pass multiplier. If i use call 1 below the parameter 3 will be automatically taken for multiplier but this is not what I wanted.

The solution for this kind of situation will be to use named argument. In call 2 I am passing the required parameter salary and yearsOfService is passed as named argument. Now i have not passed multiplier as i wanted and I am able to modify default value of yearsOfService.

Precedence of Optional Arguments while using Interfaces:
Now think of a scenario in which I define the GetBonus method into an interface and  I  also specify the default parameters too. Later I implemented this interface in a class and specify default parameters there too.
Lets look at the code below

I define an interface ISalaryCalculator having GetBonus method with default value of multiplier and yearsofService as below

I implement this method into a class SalaryCalculator. Note that I have defined the default parameters again in this implementation the value for them is different than what i defined previously in the interface.

Now the question is if I call the method of class SalaryCalculator which defalut values will be used ?

Lets see by writing a small consumable for this

look at the blow code in which I am calling this method once using class instance and later via interface.

Look at the output below

We can clearly see if we call the method using class instance directly default parameters specified in the method implementation will be used and if I call the method by casting the class instance to interface, default values specified in the interface declaration will be used !!

The above lines of code violates the "Liskov substitution principle" we should avoid using default parameter values this way. Now where we should give this depends upon your need. Some times people avoid using optional arguments in interfaces because public methods should be avoided with optional arguments for obvious reasons. Other want to give the entire definition to interfaces itself. It depend upon the requirement but the gist is that it should not be at both places.

Optional arguments were part of many languages from long time like C# got it latest. also named arguments are also great feature because of two reasons one because without it optional arguments are not complete and the other is they are providing great deal of readability to method call which make the maintenance very easy.

Wednesday, 15 May 2013

Loading assemblies using Assembly.Load , Assembly.LoadFrom and Assembly.LoadFile

While working in .Net I came across various scenarios in which I had to manually load assemblies into my application. This gave me opportunity to learn about two well known method of Assembly Loading Assembly.Load(), Assembly.LoadFrom() and one less known method Assembly.LoadFile().

Ok ..let me start by asking some questions

1. Can I load multiple versions of same assembly in a particular AppDomain ?
2. Can I have two copies of same assembly if yes which loaded assembly will have priority ?
3. The last one ....Can I have n copies of an identical assembly loaded in an application domain.? how will system behave in that case?

I hope some of you may find these questions silly and some may be thinking that how does that matter.

let me first explain what all Assembly.Load****() method does before I start answering the questions

Assembly.load takes the fully qualified assembly name and uses the .Net defined algorithm to search for an assembly. you can find the more detail here regarding  How Runtime Locates Assemblies. Using this method you can load assembly of a single version only once.

Assembly.LoadFrom takes the full path of the assembly and if you call this method it will load assembly into the application domain provided it has not been loaded from same path by this or any of  other method.The beauty of this is that  it does not load same assembly again from any other path if it has been loaded by this method before.
for example lets say i have MyAssembly.dll at following path

  1. Application output path say C:\MyApplication\bin\Debug
  2. At path C:\MyApplication\ExternalAssemblies
  3. AT path C:\TestAssemblyLoading
When the application will run this assembly will automatically be loaded from first path. Now if I try to load the assembly using Assembly.LoadFrom from path 1 it will not be loaded. but if i do so using path 2 the assembly will be loaded again. but after that if i try to load assembly from path 3 using Assembly.LoadFrom it will not be loaded now as it has already been loaded from path 2. 

In short Assembly.LoadFrom allows assembly to be loaded once from  a path from which it not been loaded yet.

So using above two methods you can load an assembly at least for two times even if everything in those assemblies is same.

This is the most lazy method you can say. It try to minimise its work and does not look for anything. If you call this method if will load the assembly every time in the AppDomain. No no don't think it that lazy if you give this method same location again it will not load the assembly again from same path but it will do if path is different. So to get an assembly loaded 10 times you need to have 10 different location where the same assembly is present.

As a thumb rule you should always rely on Assembly.Load in case you know the path of assembly is not in .Net search path use Assembly.LoadFrom() but even in that case check using AppDomain.GetAssemblies() method if the assembly is already loaded before into the AppDomain.

For long time I was confused why .Net is providing a silly method like Assembly.LoadFile() but later i came to know that their may be scenario in which the architecture of product may be such that it is loading assembly dynamically from the various locations based on the requirement but the versions are same in all folder.

For example lets say i am making an international product which have resources in an assembly which is present in the folder named after the country.For simplicity purpose i want to keep the version and assembly name same for all these assemblies.  Now the server is  present in one country and the request are coming from all over the world. The server part need to load all the assemblies with same version and name based on from which country the request is coming.  Application is retrieving resource text using reflection by loading the assembly Now to achieve this we have to use Assembly.LoadFile so that we can load all the assemblies in spite of their version and name is same.

Now i hope you must be have got the answers of all the questions i asked at start of this topic. Still some thing i want to tell you may be left ...Lets see

Ans 1. This is obviously yes, any of the above method will do that.
Ans 2. The answer is yes but the explanation of other part is tricky.

look at the below code
I have an assembly TestAssembly.dll which i have in two folders f1 and f2. I am trying to load assemblies dynamically taking advantage of Assembly.LoadFile method.

Now look at the last  line. This line will fail with the error.
[A]TestAssembly.TestClass cannot be cast to [B]TestAssembly.TestClass. Type A originates from 'TestAssembly, Version=, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location 'C:\Samples\AssemblyLoading\MultipleAssemblyLoading\f2\TestAssembly.dll'. Type B originates from 'TestAssembly, Version=, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Samples\AssemblyLoading\MultipleAssemblyLoading\MultipleAssemblyLoading\bin\Debug\TestAssembly.dll'.

To find the reason for this let look at the variable loadedAssemblies in QuickWatch window. See the result below.

The assembly TestAssembly has been loaded three times.Once because the project has a reference to it and other two we loaded by our code. Now when we try to cast "obj" into TestClass which is a type of this assembly the compiler will throw an error because the type belongs to assembly loaded in loop and we are trying to cast it into the type which is coming from the assembly referenced into the project directly . We know they are same but the compiler doesn't (a common mistake isn't it ).

We need to take a precaution while using this type of code when multiple assembly of same version has been loaded. In a small code I wrote it is very easy to find the problem but in a bigger system its can be cumbersome.
Ans 3. Obviously now you know the answer is yes and the behaviour of the system will be same as i explained above.