0

Object 上的扩展方法可以在 Object 上声明,但不能像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
4

1 回答 1

3

如果存在 Option Strict On,为什么在 Object 上声明的扩展方法的调用与在其他类型上声明的扩展方法不同?

因为您的调用上下文(您尚未显示)不可转换为Integer,但可转换为Object. 想象一下,您正在明确调用:

Me.ToString2()
Me.ToString3(Nothing)

那是转换为:

ToString2(Me)
ToString3(Me, Nothing)

不会发生ToString1(它被视为常规共享模块范围的方法),因为Me它不能隐式转换为Integer. (我不知道VB中方法调用的细节,但听起来扩展方法是在以常规方式调用模块范围的共享方法之前搜索的。)

于 2015-09-08T16:35:57.493 回答