Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does VB.NET compiler choose which extension overload to run?

Got an interesting oddity - thought someone might be able to help.

This came out of some fun with nullable types from this question:

How to check if an object is nullable?

Option Strict On

Module Test
  ' Call this overload 1
  <Extension()>
  Function IsNullable(obj As ValueType) As Boolean
    Return False
  End Function

  ' Call this overload 2
  <Extension()>
  Function IsNullable(Of T As {Structure})(obj As Nullable(Of T)) As Boolean
    Return True
  End Function

  Sub Test() 
    ' a is an integer!
    Dim a As Integer = 123

    ' calling IsNullable as an extension method calls overload 1 and returns false
    Dim result1 As Boolean = a.IsNullable()

    ' calling IsNullable as method calls overload 2 and returns true
    Dim result2 As Boolean = IsNullable(a)

    ' why? surely the compiler should treat both those calls as equivalent
  End Sub
End Module

I would expect that both calls to IsNullable would be treated the same by the compiler, but that is not the case. The extension method call uses a different overload to the normal method call even though the argument "a" is unchanged.

My question is why? What makes the compiler change its mind between the two calls?

FTR: We are using Visual Studio 2010, .NET Framework 4.

like image 280
James Close Avatar asked Sep 07 '12 13:09

James Close


People also ask

What is extension method in VB net?

Extension methods enable developers to add custom functionality to data types that are already defined without creating a new derived type. Extension methods make it possible to write a method that can be called as if it were an instance method of the existing type.

How do you identify whether a method is an extension method by seeing into its icon symbol?

The extension methods have a special symbol in intellisense of the visual studio, so that you can easily differentiate between class methods and extension methods.

What is the correct definition of extension methods?

Extension methods are defined as static methods but are called by using instance method syntax. Their first parameter specifies which type the method operates on. The parameter is preceded by the this modifier.

Why do we need extension methods in C#?

In C#, the extension method concept allows you to add new methods in the existing class or in the structure without modifying the source code of the original type and you do not require any kind of special permission from the original type and there is no need to re-compile the original type.


1 Answers

Overload 2 will ONLY work as an extension on explicitly defined Nullable(of T)'s. For example:

    Dim y As New Nullable(Of Integer)
    y.IsNullable()

This is because extension methods extend the type (or a base type), which in this case is Nullable(of T). Calling a.IsNullable() will never call overload 2. That's the easy part to figure out. This means the real question is why would overload 2 be called instead of overload 1 as a standard overloaded method call.

The CLR will determine which Overload to use by performing a "Better Conversion" check, where it implicitly converts the value(s) passed in to the type of the parameter(s) defined in the overloaded methods and then go down a checklist of rules to determine the best method to use.

From the MSDN Better Conversion Article:

If S is T1, C1 is the better conversion.

If S is T2, C2 is the better conversion.

Puting this code into Visual Studio will shows you that Overload 2 is the better conversion because the integer a (S) is the implicitly converted Nullable(of Integer) version of a (T2).

    ' a is an integer! 
    Dim a As Integer = 123

    Dim objValueType As ValueType = 123 'Or CType(a, ValueType)
    Dim objNullable As Nullable(Of Integer) = 123 'Or CType(a, Nullable(Of Integer))

    'Oh No, a compiler error for implicit conversion done for overload 1!
    Dim bolValueTypeConversionIsBetter As Boolean = (objValueType = a)

    'No error as long as Option Strict is off and it will equal True.
    Dim bolNullableConversionIsBetter As Boolean = (objNullable = a)
like image 189
NoAlias Avatar answered Nov 15 '22 09:11

NoAlias