Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does adding optional parameters change method signatures and would it trigger method missing exception?

Tags:

c#

We have several projects that are referencing library assembly lets call "myUtil", now one of the method which is referenced in several projects is,

GetData(int p1, string p2, object p3, bool p4 = false);

Now if I change above method to this,

GetData(int p1, string p2, object p3, bool p4 = false, bool p5 = false);

Do I must need to update "myUtil.dll" assembly to projects referencing it ?

WIthout referencing it I get this error which does makes sense and goes away when I update reference, but I am NOT ABLE TO VALID FIND reference where it says you must need to update references

System.MissingMethodException: Method not found: 'Void GetData(....

like image 351
Mathematics Avatar asked May 19 '15 05:05

Mathematics


2 Answers

All references must be updated.

Optional parameters are just syntactic sugar.

When you have this:

GetData(int p1, string p2, object p3, bool p4 = false);

And call it like this:

GetData(1, "p2", obj);

The compiler does this:

GetData(1, "p2", obj, false);

You'll need to recompile and redeploy all assemblies/projects that reference it.

like image 64
Brendan Green Avatar answered Oct 08 '22 04:10

Brendan Green


You don't need to remove and re-add the reference, but you do need to rebuild all of the projects that compile against the DLL. Adding an optional parameter is a source-compatible but not a binary-compatible change, because the compiler emits different IL at the call site, to include the default value as normal - the call itself looks the same in the IL whether the optional parameter was omitted or not.

For example, consider the following code:

class Test
{
    static void Main()
    {
        Foo(3);
        Foo();
    }

    static void Foo(int x = 5)
    {
    }
}

The IL for Main looks like this:

  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       16 (0x10)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldc.i4.3
    IL_0002:  call       void Test::Foo(int32)
    IL_0007:  nop
    IL_0008:  ldc.i4.5
    IL_0009:  call       void Test::Foo(int32)
    IL_000e:  nop
    IL_000f:  ret
  } // end of method Test::Main

As you can see, the constant 5 is loaded in the Main method and passed as an argument, just as 3 is explicitly. The same thing happens across assembly boundaries.

The same rules also applies to changing the values of constants, and changing the default value of an optional parameter - all of these require client rebuilds.

like image 26
Jon Skeet Avatar answered Oct 08 '22 04:10

Jon Skeet