Wrapping a .NET Class
Q from Jon P., Des Moines, IA:
I would like to inherit from a .NET class, but when I use the Inherits keyword, the
VB.NET compiler tells me that the base class is declared as non-inheritable. How can I work
around the problem?
--------------------------------------------------------------------------------
Howling Wolf Consulting Services
The Response:
Instead of using inheritance, the best solution is to define a new class that wraps the base class.
In this case, new functionality can be implemented in the wrapper class, and otherwise calls to
wrapper class methods can simply be routed directly to the wrapped class.
For instance, each of the basic .NET data types (String, Int16, Int32, Int64, etc.) is marked as
non-inheritable, so that we cannot inherit from it directly. If we want to extend the Integer (or
Int32) data type to add a number of data comparison functions (like IsGreaterThan,
IsLessThan, and IsEqualTo), we could use the following code:
Several observations are in order:
Using inheritance, all interfaces implemented by the base class are inherited by the derived
class. Since we can't use inheritance here, ordinarily we must implement the same interfaces as
the wrapped class. In this case, the Int32 data type implements the IComparable and
IFormattable interfaces but does not implement the IConvertible interface.
We must provide implementations of each of the members of the implemented interfaces. In
this case, IComparable and IFormattable have a single member each
(CompareTo and ToString, respectively).
Our SuperInteger type, like any value type, inherits implicitly from Object and
ValueType. This means that we do not need to implement members that are found in
Object or ValueType, unless we want a behavior other than the default. Because of this,
we do not need to implement the Equals, Finalize, GetHashCode, GetType,
and MemberwiseClone methods of the ValueType class.
In addition to members of implemented interfaces, we need to implement unique members of
the Int32 class. GetTypeCode and Parse largely serve to wrap calls to the identically
named Int32 members.
We need some means of initializing our SuperInteger type. If we simply assign it a value,
as in the code
Dim si As SuperInteger = 32
we get a compiler error ("Value of type 'Integer' cannot be converted to 'SuperInteger'"). To
prevent this, we've added the overloaded CSuperint static method, which converts an
incoming data type to a SuperInteger.
We can then implement whatever unique functionality we require -- in this case, an
IsGreaterThan and IsLessThan method.
Incidentally, notice that the SuperInteger structure's Value member is in some sense
the default member of the structure. This means that we don't have to specifically reference the
member when we wish to assign the structure a value.
Imports System
Imports Microsoft.VisualBasic
Public Structure SuperInteger
Implements IComparable, IFormattable
Public Value As Int32
Public Const MaxValue = Int32.MaxValue
Public Const MinValue = Int32.MinValue
Public Shared Function CSuperInt(i As Int32) As SuperInteger
Dim si As SuperInteger
si.Value = i
Return si
End Function
Public Shared Function CSuperInt(o As Object) As SuperInteger
Dim si As SuperInteger
Try
si.Value = CInt(o)
Catch
si.Value = 0
End Try
Return si
End Function
Public Function GetTypeCode() As Integer
Return Me.Value.GetTypeCode()
End Function
Public Shared Function Parse(s As String) As SuperInteger
Dim i As SuperInteger
i.Value = i.Value.Parse(s)
Return i
End Function
' Unique functionality
Public Function IsGreaterThan(o As Object) As Boolean
If IsNumeric(o) Then
If CDbl(Me.Value) > CDbl(o) Then Return True
Else
Return False
End If
End Function
Public Function IsLessThan(o As Object) As Boolean
If IsNumeric(o) Then
If CDbl(Me.Value) < CDbl(o) Then Return True
Else
Return False
End If
End Function
' Implementation of CompareTo required by IComparable
Public Function CompareTo(ByVal obj As Object) As Integer _
Implements IComparable.CompareTo
Return Me.Value.CompareTo(obj)
End Function
' Implementation of ToString required by IFormattable
Public Overloads Function ToString(format As String, _
formatProvider As IFormatProvider) _
As String _
Implements IFormattable.ToString
Dim i As Int32 = Me.Value
Return i.ToString(format, formatProvider)
End Function
End Structure