2010-12-15 19 views
3

我假设“不”,但我无法在谷歌上找到确凿的证据来支持这一假设。使用'vb.net'通用运算符重载关键字''会产生刚好1个结果,并且移除'重载'会给出更多的结果,但不会直接声明问题。.NET 4允许泛型运算符重载吗?

我的想法被赋予了一个抽象类,能够实现一个派生类可以在这种情况下使用的泛型运算符重载,当所述运算符重载必须返回一个派生类的新副本,但每个过载的代码是相同的。如果那有意义的话。

这倒是回到我以前在我的自定义枚举类的问题和重载位运算符(AndOrNot,& Xor),但是,这种特殊的想法是由一个单纯的好奇心促使“能不能做到? ”。

这里是我的自定义枚举的一个基本模样:
父,EBase没什么特别的,只是托管常见NameValue性能,再加上两个共享运营商,op_Equalityop_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我nside the 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枚举按位或运算Value物业的新EEXample.Enums对象。对于名字,我只是将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(...)是无效的,但我想不出一个合适的语法来阐明基本思想。

回答

4

根据我在language specification中可以看到的,通用运算符是不允许的。 9.8节说

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

以后当它描述声明语法时,不会像通用方法说明符那样记帐,如方法在9.2.1节中所做的那样。

+0

啊,这就是它!不幸的是,伤心,但我确定MS有其原因。也许这是未来的.NET发行版中的一个功能?不过,我发现了一个可能的替代途径。不知道它是否有效。仍然在与编译器战斗。 – Kumba 2010-12-16 01:46:13

2

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

对于顶层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实现!

是的,不是开创性的。我可以做得更好,但是这对我的需求足够好,并且不会过多地夸大代码库。它还减少了代码重复,并在技术上使维护更容易,恕我直言。

但是,仍然将基甸恩格尔伯特的答案作为接受的答案。我的问题最初问的是重载操作符是否可以通用化,并且他发现MSDN上的片段说他们不能。