在 Object 上声明的扩展方法需要比其他方法多一个参数?
Extension methods declared on Object need one more parameter than others?
对象 can be declared on Object but cannot be used like obj.ExtMethod()
的扩展方法。这是设计使然。另一方面,也可以使用任何扩展方法,如 ExtMethod(obj)
。 为什么调用在 Object 上声明的扩展方法不同于在其他类型上声明的扩展方法? 我正在寻找这背后的逻辑。或者这是一个错误?
要找出区别,请看下面的例子并比较普通的 ToString1()
和 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
在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
添加的详细信息:(最少完整的工作示例 – 3 个文件 – 包括上面一个)
完整调用上下文: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
完整调用上下文:Class 不同于 Class1 – 没有发布有问题的问题,但是奇怪的效果:
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
完整调用上下文:模块 – 没有问题:
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
Why calling of extension methods declared on Object differ from extension methods declared on other types if Option Strict On is present?
因为您的调用上下文(您未显示)无法转换为 Integer
,但可以转换为 Object
。假设您正在明确调用:
Me.ToString2()
Me.ToString3(Nothing)
转换为:
ToString2(Me)
ToString3(Me, Nothing)
不会发生在 ToString1
中(它被视为常规的共享模块范围的方法),因为 Me
不是隐式可转换的至 Integer
。 (我不知道 VB 中方法调用的细节,但听起来像是在以常规方式调用模块范围的共享方法之前搜索扩展方法。)
对象 can be declared on Object but cannot be used like obj.ExtMethod()
的扩展方法。这是设计使然。另一方面,也可以使用任何扩展方法,如 ExtMethod(obj)
。 为什么调用在 Object 上声明的扩展方法不同于在其他类型上声明的扩展方法? 我正在寻找这背后的逻辑。或者这是一个错误?
要找出区别,请看下面的例子并比较普通的 ToString1()
和 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
在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
添加的详细信息:(最少完整的工作示例 – 3 个文件 – 包括上面一个)
完整调用上下文: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
完整调用上下文:Class 不同于 Class1 – 没有发布有问题的问题,但是奇怪的效果:
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
完整调用上下文:模块 – 没有问题:
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
Why calling of extension methods declared on Object differ from extension methods declared on other types if Option Strict On is present?
因为您的调用上下文(您未显示)无法转换为 Integer
,但可以转换为 Object
。假设您正在明确调用:
Me.ToString2()
Me.ToString3(Nothing)
转换为:
ToString2(Me)
ToString3(Me, Nothing)
不会发生在 ToString1
中(它被视为常规的共享模块范围的方法),因为 Me
不是隐式可转换的至 Integer
。 (我不知道 VB 中方法调用的细节,但听起来像是在以常规方式调用模块范围的共享方法之前搜索扩展方法。)