Sunday, July 21, 2013

C#/VB.NET Optional Parameters and the MissingMethodException Exception

Optional Parameters 

Optional parameters is a useful feature in C# and VB.NET languages. Adding an optional parameter to a method can sometimes make re-factoring a bit easier and less invasive. There is however a catch one should know. I ran into this situation a few days ago and here is my attempt to describe it:

Initially

Suppose you have a library, let's call it OptionsLib. In this class library lets say we have class called Common. In this Common class there is a method call DoSomeWork whose signature looks initially like

public void DoSomeWork(){
   DoStepOne();
   DoStepTwo();
   DoSomeOtherStep();

}

Now we have a consumer of this OptionsLib library and let's call it OptionsClient and it exists in its own assembly. So we have two assemblies: OptionsLib v1.0.0.0 and OptionsClient v1.0.0.0.

New Version: Minor Change

You've decided to make a minor change to your OptionsLib.Common class. Namely you wanted to add some conditional logic to the DoSomeWork method. So the new method would look something like:

public void DoSomeWork(bool someCondition = true){
   DoStepOne();
   DoStepTwo();
   if(someCondition){
       DoSomeOtherStep();
   }
}

There are probably other libraries that depend on the OptionsLib library so making the new parameter optional alleviates you from having to change the way the method called everywhere. The existing behavior is retained by making the new parameter optional and giving it a default value of true. So now re-compiling the whole solution will yield no errors as a result of the new optional parameter. The compiler will realize the new parameter is optional and will take care of passing the default value for you everywhere the method DoSomeWork is called.

The Issue: System.MissingMethodException

Let's say you found a bug in some of the libraries that use OptionsLib library or a change is made to one of its clients and you wanted to push that change to existing installations. In our example, suppose we may have fixed some bug or added a feature to the OptionsClient.dll assembly. So now OptionsClient.dll is compiled against the new version of OptionsLib, the version with the optional parameter change. In the existing installations however, the OptionsLib does not have the optional parameter we added.

For the most part placing the new OptionsClient.dll assembly in existing installations will be OK. It will find its referenced assemblies in the existing installations and everything seems to work fine. Until it starts calling the method DoSomeWork which in the new version has an optional parameter but not in the existing version. So in reality the new OptionsClient call of DoSomeWork looks like:
...DoSomeWork(true); // my understanding is that the compiler passes true for you                                               // because it's optional and the default is true
When the above call is made the runtime will complain because there is no method named DoSomeWork in v1.0.0.0 of OptionsLib that takes a boolean; there is one with no parameters at all but it's not what was called. The runtime then throws the System.MissingMethodException exception. So you'll realize that you may need to also recompile and ship the OptionsLib v1.0.0.1 the one with optional parameter

I Learned

Optional parameters are useful but sometimes adding them to a library can break dependents assemblies on this the changed library when the dependent assemblies are deployed alone without the changed library. I think I'd prefer method overloading when re-factoring.

http://msdn.microsoft.com/en-us/library/dd264739.aspx optional parameters
http://msdn.microsoft.com/en-us/library/zk1a255s(v=vs.80).aspx MissingMethodException