Operator overload has no named alternate method

ID

vbnet.maintainability.operator_overloads_have_named_alternates

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Api Design

Language

VB.NET

Description

Reports an overloaded operator whose declaring type does not also expose the named method that the .NET design guidelines pair with that operator - Add for +, Subtract or Negate for -, Multiply for *, Divide for /, Concatenate for &, BitwiseAnd for And, BitwiseOr for Or and LogicalNot for Not. A type that declares both the operator and its named method is not reported, in either declaration order.

Rationale

Operator overloading is an optional language feature, so an operator alone does not make the behaviour reachable from every .NET language that may consume the assembly. A caller in a language without operator overloading, and any caller working through reflection, late binding, an expression tree or a dynamically generated call, has no way to invoke op_Addition other than by name - and that name is a compiler-generated detail, not part of a documented API. The named alternate is also what appears in IntelliSense and in generated API documentation, so without it the capability is effectively invisible to anyone browsing the type.

The following code illustrates the pattern detected by this rule:

    Public Currency As String

    ' FLAGGED: Operator overload has no named alternate method
    Public Shared Operator +(ByVal a As Money, ByVal b As Money) As Money
        Return New Money With {.Amount = a.Amount + b.Amount, .Currency = a.Currency}
    End Operator

    ' FLAGGED: Operator overload has no named alternate method
    Public Shared Operator -(ByVal a As Money, ByVal b As Money) As Money
        Return New Money With {.Amount = a.Amount - b.Amount, .Currency = a.Currency}
    End Operator

    ' FLAGGED: Operator overload has no named alternate method
    Public Shared Operator *(ByVal a As Money, ByVal factor As Decimal) As Money
        Return New Money With {.Amount = a.Amount * factor, .Currency = a.Currency}
    End Operator

    ' FLAGGED: Operator overload has no named alternate method
    Public Shared Operator /(ByVal a As Money, ByVal divisor As Decimal) As Money
        Return New Money With {.Amount = a.Amount / divisor, .Currency = a.Currency}
    End Operator
End Structure

Public Class Vector3

    Public Shared Function Multiply(ByVal a As Vector3, ByVal k As Double) As Vector3
        Return a

Remediation

Add a Public Shared Function with the guideline name for the operator, and have the operator delegate to it so the two can never drift apart. For example, keep the arithmetic in Public Shared Function Add(a As Money, b As Money) As Money and reduce the operator body to Return Add(a, b). Use Negate for the unary minus and Subtract for the binary one.

Configuration

This detector does not need any configuration.