Drawing.Rectangle 的写作扩展

Writing extension for Drawing.Rectangle

Drawing.Rectangle 有方法

Dim r As Drawing.Rectangle = Drawing.Rectangle.FromLTRB(...)

我想写一个类似于那个函数的扩展方法。扩展方法将创建一个包含所有给定点的矩形。

我写过这样的方法,但是"Rectangle"没注意到有这个新方法

当我尝试访问该方法时,Intellisense 找不到它。

我已经在这样的模块中声明了扩展:

<Extension()>
Public Function FromPoints(ByVal points As List(Of Drawing.Point)) As Drawing.Rectangle

    Dim leastX As Integer = 0
    Dim maxX As Integer = 0
    Dim leastY As Integer = 0
    Dim maxY As Integer = 0

    Dim bDone As Boolean = False

    For Each p As Point In points
        If Not bDone Then
            bDone = True
            leastX = p.X
            maxX = p.X
            leastY = p.Y
            maxY = p.Y
        Else
            If p.X < leastX Then
                leastX = p.X
            End If
            If p.X > maxX Then
                maxX = p.X
            End If
            If p.Y < leastY Then
                leastY = p.Y
            End If
            If p.Y > maxY Then
                maxY = p.Y
            End If
        End If
    Next

    Return Drawing.Rectangle.FromLTRB(leastX, leastY, maxX, maxY)

End Function

我是否遗漏了任何让它发挥作用的东西?

您引用的 FromLTRB 方法是 Shared,即它是 Rectangle 类型的成员,但不是 Rectangle 实例的成员。请注意,您在 Rectangle 上调用它,而不是在 A Rectangle.

上调用它

扩展方法只能作为实例成员使用。您不能编写在 Rectangle 类型上调用的扩展方法,而只能编写在 Rectangle 实例上调用的扩展方法。您调用它的实例实际上由第一个参数表示。您的扩展方法必须如下所示:

Imports System.Runtime.CompilerServices

Public Module RectangleExtensions

    <Extension>
    Public Function FromPoints(source As Rectangle, points As List(Of Point)) As Rectangle
        '...
    End Function

End Module

然后你必须这样称呼它:

Dim rect As Rectangle
Dim points As New List(Of Point)

'...

Dim newRect = rect.FromPoints(points)

这并不完全理想,因为您必须有一个 Rectangle 开始,但没有办法解决这个问题,因为扩展方法需要调用被扩展类型的实例。

顺便说一下,我倾向于这样写那个方法:

Imports System.Runtime.CompilerServices

Public Module RectangleExtensions

    <Extension>
    Public Function FromPoints(source As Rectangle, points As IEnumerable(Of Point)) As Rectangle
        Dim pointArray = points.ToArray()
        Dim allX = pointArray.Select(Function(p) p.X).ToArray()
        Dim allY = pointArray.Select(Function(p) p.Y).ToArray()

        Return Rectangle.FromLTRB(allX.Min(),
                                  allY.Min(),
                                  allX.Max(),
                                  allY.Max())
    End Function

End Module

使用IEnumerable(Of Point)使方法更灵活,使用LINQ使方法更简洁。 LINQ 实际上会使性能变差,但您必须有一个非常大的 Points 列表才能产生明显的差异。

编辑:

我应该明确指出,扩展方法需要一个实例,而这种情况在调用该方法之前不需要实例,这意味着您不应在这种情况下使用扩展方法。只需编写一个方法,获取 Points 和 returns 一个 Rectangle 的列表并将其放在适当的位置:

Public Function RectangleFromPoints(points As IEnumerable(Of Point)) As Rectangle
    Dim pointArray = points.ToArray()
    Dim allX = pointArray.Select(Function(p) p.X).ToArray()
    Dim allY = pointArray.Select(Function(p) p.Y).ToArray()

    Return Rectangle.FromLTRB(allX.Min(),
                              allY.Min(),
                              allX.Max(),
                              allY.Max())
End Function