Разрешены ли общие перегрузки операторов в .NET 4? - PullRequest
4 голосов
/ 15 декабря 2010

Я предполагаю «Нет», но не могу найти убедительных доказательств в Google, подтверждающих это предположение.Использование ключевых слов «vb.net« универсальная перегрузка оператора »» дает ровно 1 результат, а удаление «перегрузки» дает больше, но не дает прямого решения вопроса.

Мое мышление дано абстрактному классуБыло бы здорово иметь возможность реализовать универсальную перегрузку оператора, которую производный класс может использовать в таком случае, когда указанная перегрузка оператора должна возвращать новую копию производного класса, но код для каждой перегрузки одинаков.Если это имеет смысл.

Это возвращает нас к моим предыдущим вопросам о моем пользовательском классе Enum и перегрузке побитовых операторов (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

Я должен определить перегрузку оператора для 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 объект, содержащий свойство Bitwise-Or'ed Value родительских перечислений EExample.Что касается имени, я просто объединяю свойства Name вместе с символом канала, пока не подумаю о чем-то лучшем.

Предположим, у меня есть 20 классов enum, похожих на 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.Enums соответствует ограничению интерфейса IEnums, и автоматически поставьте T.

То есть, или я просто плаваю здесь в ручье без весла и чрезмерного анализа вещей.Но это интересная мысль, нет?Каков консенсус StackOverflow?Нужно ли мне немного отложить Spice?

PS: Я знаю, что в последнем примере Return New T( ... ) недействителен, но я не могу придумать правильногосинтаксис, который сформулировал бы основную идею.

Ответы [ 2 ]

5 голосов
/ 15 декабря 2010

Согласно тому, что я вижу в спецификации языка , универсальные операторы не допускаются. Раздел 9.8 говорит

Типом хотя бы одного из операндов или возвращаемого значения должен быть тип, содержащий оператор.

и позже, когда он описывает синтаксис объявления, не учитывает общий спецификатор, как это делают методы в разделе 9.2.1.

3 голосов
/ 16 декабря 2010

Сам нашел «работоспособное» решение.

Для верхнего уровня 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 обратно вызывающей стороне. В производных Enums (то есть 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, и не повторять каждый раз в моих многочисленных производных классах enum. Эти перечислимые классы просто вызывают реализацию родителя и используют обобщения для передачи своей неопределяемой Enums реализации!

Да, не новаторский. Я мог бы сделать лучше, но это работает достаточно хорошо для моих нужд и не слишком завышает кодовую базу. Это также уменьшает дублирование кода и технически упрощает обслуживание, ИМХО.

Тем не менее, оставляя ответ Гедеона Энгельберта в качестве принятого ответа. Сначала я спросил, можно ли обобщать перегруженные операторы, и он обнаружил в MSDN фрагмент, в котором говорится, что они не могут.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...