我假设“不”,但我无法找到谷歌的确凿证据支持这一假设。使用'vb.net'的关键字泛型运算符重载“'只产生1个结果,删除'重载'会产生更多,但没有直接声明该问题。
我的思考是一个抽象类,能够实现一个泛型运算符重载是很棒的,派生类可以在这种情况下使用,当所述运算符重载必须返回派生类的New副本时,但每个重载的代码是相同的。如果这是有道理的。
这回顾了我之前关于我的自定义Enum类的问题,并重载了按位运算符(And
,Or
,Not
和& Xor
),但是,这个特殊的想法是出于好奇的“它可以做到吗?”而引发的。
这是我的一个自定义枚举基本上是什么样的:
父[{1}}并不特别,只托管常见的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
定义中为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
无效,但我无法想出能够表达基本概念的正确语法。
答案 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上发现了他们不能使用的代码段。