How Do VB.NET Optional Parameters work 'Under

2019-06-21 19:00发布

问题:

Let's say we have the following method declaration:

Public Function MyMethod(ByVal param1 As Integer, _
    Optional ByVal param2 As Integer = 0, _
    Optional ByVal param3 As Integer = 1) As Integer

    Return param1 + param2 + param3
End Function

How does VB.NET make the optional parameters work within the confines of the CLR? Are optional parameters CLS-Compliant?

回答1:

Interestingly, this is the decompiled C# code, obtained via reflector.

public int MyMethod(int param1, 
                   [Optional, DefaultParameterValue(0)] int param2, 
                   [Optional, DefaultParameterValue(1)] int param3)
{
    return ((param1 + param2) + param3);
}

Notice the Optional and DefaultParameterValue attributes. Try putting them in C# methods. You will find that you are still required to pass values to the method. In VB code however, its turned into Default! That being said, I personally have never use Default even in VB code. It feels like a hack. Method overloading does the trick for me.

Default does help though, when dealing with the Excel Interop, which is a pain in the ass to use straight out of the box in C#.



回答2:

Contrary to popular belief, optional parameters do appear to be CLS-compliant. (However, my primary check for this was to mark the assembly, class and method all with the CLSCompliant attribute, set to True.)

So what does this look like in MSIL?

.method public static int32  MyMethod(int32 param1,
                                      [opt] int32 param2,
                                      [opt] int32 param3) cil managed
{
  .custom instance void [mscorlib]System.CLSCompliantAttribute::.ctor(bool) = ( 01 00 01 00 00 ) 
  .param [2] = int32(0x00000000)
  .param [3] = int32(0x00000001)
  // Code size       11 (0xb)
  .maxstack  2
  .locals init ([0] int32 MyMethod)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  add.ovf
  IL_0004:  ldarg.2
  IL_0005:  add.ovf
  IL_0006:  stloc.0
  IL_0007:  br.s       IL_0009
  IL_0009:  ldloc.0
  IL_000a:  ret
} // end of method Module1::MyMethod

Note the [opt] markings on the parameters -- MSIL supports this natively, without any hacks. (Unlike MSIL's support for VB's Static keyword, which is another topic altogether.)

So, why aren't these in C#? I can't answer that, other than my speculation that it might be a presumed lack of demand. My own preference has always been to specify the parameters, even if they were optional -- to me, the code looks cleaner and is easier to read. (If there are omitted parameters, I often look first for an overload that matches the visible signature -- it's only after I fail to find one that I realize that optional parameters are involved.)