Both VB.NET and C# now support operator overloading, which means that you can define the behavior for standard operators such as +, −, /, and *. You can also define type conversion operators that control how casting is handled between different types.
The syntax for operator overloading is very similar to a static method except that it includes the Operator keyword, as shown in the following example:
C#
public class OperatorBaseClass{ private int m_value; public static OperatorBaseClass operator +(OperatorBaseClass op1 , OperatorBaseClass op2 ) { OperatorBaseClass obc =new OperatorBaseClass(); obc.m_value = op1.m_value + op2.m_value; return obc; } }
VB.NET
Public Class OperatorBaseClass Private m_value As Integer Public Shared Operator +(ByVal op1 As OperatorBaseClass, _ ByVal op2 As OperatorBaseClass) As OperatorBaseClass Dim obc As New OperatorBaseClass obc.m_value = op1.m_value + op2.m_value Return obc End Operator End Class
In both languages, a binary operator overload requires two parameters and a return value. The first value, op1, appears to the left of the operator, with the second on the right side. Clearly, the return value is substituted into the equation in place of all three input symbols. Although it makes more sense to make both input parameters and the return value the same type, this is not necessarily the case, and this syntax can be used to define the effect of the operator on any pair of types. The one condition is that one of the input parameters must be of the same type that contains the overloaded operator.
A type conversion is the process of converting a value of one type to another type. These can be broadly categorized into widening and narrowing conversions. In a widening conversion, the original type has all the necessary information to produce the new type. As such, this conversion can be done implicitly and should never fail. An example would be casting a derived type to its base type. Conversely, in a narrowing conversion, the original type may not have all the necessary information to produce the new type. An example would be casting a base type to a derived type. This conversion cannot be guaranteed, and needs to be done via an explicit cast.
The following example illustrates conversions between two classes, Person and Employee. Converting from a Person to an Employee is a well-known conversion, because an employee's initial wage can be defined as a multiple of their age (for example, when they are employed). However, converting an Employee to a Person is not necessarily correct, because an employee's current wage may no longer be a reflection of the employee's age:
C#
public class Employee { ... static public implicit operator Employee(Person p) { Employee emp=new Employee(); emp.m_Name=p.Name; emp.m_Wage = p.Age * 1000; return emp; } static public explicit operator Person(Employee emp) { Person p = new Person(); p.Name = emp.m_Name; p.Age=(int)emp.m_Wage/1000; return p; } }
VB.NET
Public Class Employee ... Public Shared Widening Operator CType(ByVal p As Person) As Employee Dim emp As New Employee emp.m_Name = p.Name emp.m_Wage = p.Age * 1000 Return emp End Operator Public Shared Narrowing Operator CType(ByVal emp As Employee) As Person Dim p As New Person p.Name = emp.m_Name p.Age = CInt(emp.m_Wage / 1000) Return p End Operator End Class
Now that you know how to overload operators and create your own type conversions, this section serves as a disclaimer stating that static methods should be avoided at all costs. Because both type conversions and operator overloads are static methods, they are only relevant for the type for which they are defined. This can cause all manner of grief and unexpected results when you have complex inheritance trees. To illustrate how you can get unexpected results, consider the following example:
Public Class FirstTier Public Value As Integer Public Shared Widening Operator CType(ByVal obj As FirstTier) As String Return "First Tier: " & obj.Value.ToString End Operator Public Overrides Function ToString() As String Return "First Tier: " & Me.Value.ToString End Function End Class Public Class SecondTier Inherits FirstTier Public Overloads Shared Widening Operator CType(ByVal obj As SecondTier) _ As String Return "Second Tier: " & obj.Value.ToString End Operator Public Overrides Function ToString() As String Return "Second Tier: " & Me.Value.ToString End Function End Class 'Sample code to call conversion and tostring functions Public Class Sample Public Shared Sub RunSampleCode Dim foo As New SecondTier foo.Value = 5 Dim bar As FirstTier = foo Console.WriteLine("<SecondTier> ToString " & vbTab & foo.ToString) Console.WriteLine("<SecondTier> CStr " & vbTab & CStr(foo)) Console.WriteLine("<FirstTier> ToString " & vbTab & bar.ToString) Console.WriteLine("<FirstTier> CStr " & vbTab & CStr(bar)) End Sub End Class
The output from this sample is as follows:
<SecondTier> ToString Second Tier: 5 <SecondTier> CStr Second Tier: 5 <FirstTier> ToString Second Tier: 5 <FirstTier> CStr First Tier: 5
As you can see from the sample, the last cast gives an unusual response. In the first two casts, you are dealing with a SecondTier variable, so both ToString and CStr operations are called from the SecondTier class. When you cast the object to a FirstTier variable, the ToString operation is still routed to the SecondTier class, because this overrides the functionality in the FirstTier. However, because the CStr operation is a static function, it is routed to the FirstTier class, because this is the type of variable. Clearly, the safest option here is to ensure that you implement and call the ToString method on the instance variable. This rule holds for other operators, such as equals, which can be overridden instead of defining the = operator. In cases where you need a +, −, / or * operator, consider using nonstatic Add, Subtract, Divide, and Multiply operators that can be run on an instance.
As the final word on operator overloading and type conversion, if you find yourself needing to write either type of static method you should reassess your design to see if there is an alternative that uses instance methods such as Equals or ToString.
3.147.13.192