对象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
课堂上的用法:
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个文件 - 包括上述文件)
完整的调用环境:类:
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
完整的调用环境:类与 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
答案 0 :(得分:3)
如果存在Option Strict On,为什么调用在Object上声明的扩展方法与在其他类型上声明的扩展方法不同?
因为您的通话环境(您尚未显示)无法转换为Integer
,但可转换为Object
。想象一下你明确地打电话:
Me.ToString2()
Me.ToString3(Nothing)
转换为:
ToString2(Me)
ToString3(Me, Nothing)
不会与ToString1
一起发生(被视为常规的共享模块范围方法),因为Me
无法隐式转换为Integer
。 (我不知道VB中方法调用的细节,但听起来像是在以常规方式调用模块范围的共享方法之前搜索扩展方法。)