.NET 4允许使用通用运算符重载吗?

4
我认为答案是否定的,但我在谷歌上没有找到确凿的证据来支持这个假设。使用“vb.net“通用运算符重载”这些关键词只能得到一个结果,移除“overload”可以得到更多结果,但没有直接说明这个问题的语句。
我的想法是,如果给定一个抽象类,那么实现一个通用的运算符重载会很棒,派生类可以在这种情况下使用它,当这个运算符重载必须返回一个派生类的新副本时,每个重载的代码都是相同的。如果这有任何意义的话。
这涉及到我之前关于自定义枚举类和重载按位运算符(And,Or,Not和Xor)的问题,但是,这个特定的想法仅仅是出于好奇心而引发的。
这是我的一个自定义枚举类的基本样子: 父类EBase并不特别,只是拥有常见的Name和Value属性,以及两个共享运算符op_Equality和op_Inequality。
Friend NotInheritable Class EExample
    Inherits EBase

    Private Sub New()
    End Sub

    Friend Shared Function GetValue(ByVal Name As String) As Enums
        Dim tmpOffset As Int32 = Array.IndexOf(_Names, Name)
        Return If(HasContent(Name), If(tmpOffset <> -1, Values(tmpOffset), Nothing), Nothing)
    End Function


    ' Num of Enums defined.
    Friend Shared ReadOnly MaxEnums As Int32 = 5

    ' String literals.
    Private Shared ReadOnly _Names As String() = New String() _
        {"one_adam", "two_boy", "three_charles", "four_david", "five_edward"}

    ' Enums.
    Friend Shared ReadOnly OneA As New Enums(_Names(0), 1)
    Friend Shared ReadOnly TwoB As New Enums(_Names(1), 2)
    Friend Shared ReadOnly ThreeC As New Enums(_Names(2), 4)
    Friend Shared ReadOnly FourD As New Enums(_Names(3), 8)
    Friend Shared ReadOnly FiveE As New Enums(_Names(4), 16)


    ' Enum Values Array.
    Friend Shared ReadOnly Values As Enums() = New Enums() _
        {OneA, TwoB, ThreeC, FourD, FiveE}


    Friend NotInheritable Class Enums
        Inherits EBase

        Private Sub New()
        End Sub

        Friend Sub New(ByVal Name As String, ByVal Value As Int32)
            MyBase.Name = Name
            MyBase.Value = Value
        End Sub
    End Class
End Class

以下是如何使用这些工具的方法:
Dim Foo As EExample.Enums
Foo = EExample.TwoB
Debug.Print(Foo.Name)

将打印two_boy

现在,假设我想要执行以下操作:

Dim Foo as EExample.Enums
Foo = EExample.OneA Or EExample.FiveE

我必须在 EExample.Enums 定义中定义一个 Or 运算符重载,该运算符应该如何定义?

Public Shared Operator Or(ByVal lhOp As Enums, ByVal rhOp As Enums) As Enums
    Return New Enums(String.Concat(lhOp.Name, "|"c, rhOp.Name),
                     lhOp.Value Or rhOp.Value, True)
End Operator

我需要返回一个新的EEXample.Enums对象,其中包含父EExample枚举的按位或Value属性。 对于名称,我只需使用管道字符将Name属性连接在一起,直到我想到更好的方法。
假设我有20个类似于EExample的枚举类。 即使在IDE中看起来完全相同,我也必须为每个定义复制所有运算符重载代码。 但是,在IL中,每个重载都特定于包含父枚举类:
.method public specialname static class MyAssembly.EExample/Enums 
        op_BitwiseOr(class MyAssembly.EExample/Enums lhOp,
                     class MyAssembly.EExample/Enums rhOp) cil managed
{ ... }

但是!如果在EBase中定义一个通用的运算符重载,就可以解决这个问题!

Friend Interface IEnums
    Property Name As String
    Property Value As Int32
End Interface

Public Shared Operator Or(Of T As IEnums)(ByVal lhOp As T, ByVal rhOp As T) As T
    Return New T(String.Concat(lhOp.Name, "|"c, rhOp.Name),
                 lhOp.Value Or rhOp.Value, True)
End Operator

理论上来说,调用EExample.OneA Or EExample.FiveE应该可以工作,因为编译器会知道从EBase调用泛型操作符重载,知道EExample.EnumsIEnums接口约束匹配,并自动提供T。或者我只是在没有桨的情况下游泳并过度分析事情。但这是一个有趣的想法,StackOverflow的共识是什么?我需要减少香料的使用吗?PS: 我知道,在最后一个示例中,Return New T( ... )是无效的,但我想不出能表达基本思想的正确语法。
2个回答

5
根据我在规范说明书中所看到的,不允许使用通用运算符。第9.8节说:

至少一个操作数或返回值的类型必须是包含运算符的类型。

稍后在描述声明语法时,与第9.2.1节中方法一样,没有考虑通用限定符。


啊,就是这个!很遗憾,但我确信微软有它的理由。也许这是未来 .NET 发布中的一个功能?不过,我找到了一个可能的替代方法来追求它。还不知道能否成功,目前还在与编译器作斗争。 - Kumba

3

我自己找到了一个“可行的”解决方案。

对于顶层的EBase,我将接口(IEnumBase)公开为Friend,然后在EBase中创建通用方法来处理重载运算符:

Protected Shared Function _
op_BitwiseOr(Of T As {IEnumBase, Class})(ByVal lhOp As T, ByVal rhOp As T, ByVal RetEnum As T) As T
    RetEnum.Name = String.Concat(lhOp.Name, "|"c, rhOp.Name)
    RetEnum.Value = (lhOp.Value Or rhOp.Value)

    Return RetEnum
End Function

在这里的技巧是通用方法只是将RetEnum返回给调用者。在派生的枚举类型(即EExample)中,我有:
Public Shared Shadows Operator Or(ByVal lhOp As Enums, ByVal rhOp As Enums) As Enums
    Return EBase.op_BitwiseOr(lhOp, rhOp, New Enums)
End Operator

这使我可以将较笨重的代码仅在 EBase 中定义一次,而不是每次在我的许多派生枚举类中复制。这些枚举类只需调用父类的实现并使用泛型传递其子定义的 Enums 实现即可!
是的,并没有突破性的进展。我可以做得更好,但这对我的需求足够好,不会过度膨胀代码库。它还减少了代码重复,并从技术上讲使维护更容易,依我之见。
然而,我仍将 Gideon Engelberth 的答案保留为被接受的答案。我的问题最初询问是否可以将重载运算符泛型化,而他在 MSDN 上找到了不能的代码片段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接