.NET 4中是否允许泛型运算符重载?

时间:2010-12-15 03:05:15

标签: vb.net generics operator-overloading

我假设“不”,但我无法找到谷歌的确凿证据支持这一假设。使用'vb.net'的关键字泛型运算符重载“'只产生1个结果,删除'重载'会产生更多,但没有直接声明该问题。

我的思考是一个抽象类,能够实现一个泛型运算符重载是很棒的,派生类可以在这种情况下使用,当所述运算符重载必须返回派生类的New副本时,但每个重载的代码是相同的。如果这是有道理的。

这回顾了我之前关于我的自定义Enum类的问题,并重载了按位运算符(AndOrNot和& Xor),但是,这个特殊的想法是出于好奇的“它可以做到吗?”而引发的。

这是我的一个自定义枚举基本上是什么样的:
父[{1}}并不特别,只托管常见的EBaseName属性,以及两个共享运算符Valueop_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 定义中为Or 定义一个运算符重载。该运算符如何超载?

EExample.Enums

我必须返回一个新的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个枚举的按位或Value属性。对于名称,我只是将EExample属性与管道字符连接起来,直到我想到更好的东西。

假设我有20个类似于Name的枚举类。我必须为每个定义复制所有运算符重载代码,即使在IDE中,它看起来完全相同。但是,在IL中,每个重载都特定于包含的父枚举类:

EExample

但是!如果在.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.Enums界面约束,并自动提供IEnums

我或者我只是在没有划桨和过度分析的情况下游过某条小溪。但这是一个有趣的想法,不是吗? StackOverflow的共识是什么?我需要稍微裁掉Spice吗?

PS:我知道,在上一个示例中,T无效,但我无法想出能够表达基本概念的正确语法。

2 个答案:

答案 0 :(得分:5)

根据我在language specification中可以看到的内容,不允许使用泛型运算符。第9.8节说

  

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

以及稍后当它描述声明语法时,不会像9.2.1节中的方法那样对泛型说明符进行计算。

答案 1 :(得分:3)

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

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

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上发现了他们不能使用的代码段。