Extension methods on Object can be declared on Object but cannot be used like obj.ExtMethod()
. This is by design. On the other hand, any extension method can be also used like ExtMethod(obj)
. Why calling of extension methods declared on Object differ from extension methods declared on other types? I'm seeking for logic behind this. Or is it a bug?
To spot the difference, please see below example and compare ordinary ToString1()
to ToString2()
/ToString3()
.
Imports System.Runtime.CompilerServices
Module CompilerExtensionsModule
' standard one, works as expected
<Extension>
Function ToString1(value As Integer) As String
Return value.ToString()
End Function
' obj isn't expected as parameter on actual usage, context is supplied instead
<Extension>
Function ToString2(obj As Object) As String
Return If(obj Is Nothing, "", obj.ToString())
End Function
' this is way how to have obj as parameter - first parameter is ignored
<Extension>
Function ToString3(base As Object, obj As Object) As String
Return If(obj Is Nothing, "", obj.ToString())
End Function
' let's try with something different than Object
<Extension>
Function ToStringClass1(obj As Class1) As String
Return obj.ToString()
End Function
End Module
Usage in class:
ToString1(3) ' as expected - 1 parameter declared, 1 expected
ToString2() ' 1 parameter declared, no parameters expected in call
ToString3(Nothing) ' 2 parameters declared, 1 expected in call - passed as second parameter
Added details: (minimum complete working example – 3 files – including the above one)
Full calling context: Class:
Public Class Class1
Sub Action1()
Dim value1 As Integer = 1
Dim obj1 As Object = Nothing
Dim obj2 As New Class1
Console.WriteLine(ToString1(value1))
Console.WriteLine(ToString2())
Console.WriteLine(ToString3(obj1))
Console.WriteLine(ToStringClass1())
End Sub
End Class
Full calling context: Class different from Class1 – no issues posted in question, but weird effects:
Public Class Class2
Sub Action1()
Dim value1 As Integer = 1
Dim obj1 As Object = Nothing
Dim obj2 As New Class1
Console.WriteLine(ToString1(value1))
Console.WriteLine(ToString2())
Console.WriteLine(ToString3(obj1))
Console.WriteLine(ToStringClass1(obj2))
obj2.ToString2()
ToString2(obj2) ' INVALID - won't compile in any class (but will do in any module)
ToString3(obj2) ' EDIT: VALID because two parameters are actually supplied here
' EDIT (see comments below the answer):
CompilerExtensionsModule.ToString2(obj2) ' VALID - switching the context solves it
' Note: for ext.mehods of Object, this form of call is needed in any class
' Reason: any class is descendant of Object => VB wants to supply 1st parameter
' in calling context of class => use calling context of ext.module instead
End Sub
End Class
Full calling context: Module – no issues:
Module Module1
Sub Main()
Dim value1 As Integer = 1
Dim obj1 As Object = Nothing
Dim obj2 As New Class1
Console.WriteLine(ToString1(value1))
Console.WriteLine(ToString2(obj1))
Console.WriteLine(ToString3(obj1, obj1))
Console.WriteLine(ToStringClass1(obj2))
' unlike in Class2, no issues here:
obj2.ToString2()
ToString2(obj2)
End Sub
End Module