---------------------------------------------------------------------------------------

View Previous Wolf Tracks Columns

Submit a Question to Wolf Tracks


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
Wolf Tracks

A Q&A Forum

View Previous Columns

Submit a Question

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