vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#

https://www.vbarchiv.net
Rubrik: Variablen/Strings   |   VB-Versionen: VB.NET16.05.07
Der CType-Operator in VB 2005

Erstellung von Klassen, die wie integrierte Datentypen verwendet werden können.

Autor:   Manfred BohnBewertung:  Views:  11.014 
ohne HomepageSystem:  WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11kein Beispielprojekt 

Durch den CType-Operator lassen sich in VB 2005 Klassen erstellen, die im Code wie integrierte Datentypen verwendet werden können.

Als Beispiel dient die Klasse 'cDouble'.
Diese Klasse kapselt einen Double-Wert und stellt Operatoren für die vier Grundrechenarten zur Verfügung. Da in VB.Net die IEEE-kompatiblen Gleitkomma-Variablen (SINGLE, DOUBLE) keine Ausnahme auslösen, wenn es zu einem Überlauf oder einer Division durch 0 kommt, ist in diesen Fällen die Ausnahme 'Overflow' - entsprechend dem 'klassischen' VB-Verhalten - in 'cDouble' wieder integriert worden ('DivideByZero' wird jedoch ebenfalls als 'Overflow' gemeldet).

Durch geeignete Belegung der klassenglobalen Konstanten 'cMinValue' und 'cMaxValue' kann der akzeptierte Wertebereich der cDouble-Instanzen weiter eingegrenzt werden.
Dies ist nützlich bei der Modellierung. Hat man z.B. Variable, die Temperatur-Angaben enthalten sollen, ist es vermutlich zweckmäßig, den Wertebereich dieser Klasse von Variablen auf +/-50 einzugrenzen.

Die Vergleichsoperatoren der Klasse 'cDouble' führen ausprägungsabhängige Epsilon-Vergleiche durch. Welches Werteintervall dabei als 'gleich' akzeptiert wird, kann durch die klassenglobale Konstante 'cEpsilon' gesteuert werden.

Die Routine 'cDouble_Demo' zeigt die Verwendung der Klasse 'cDouble' im VB-Code.

Man beachte, dass weder das Schlüsselwort NEW bei der Erstellung eines Instanz, noch die explizite Konvertierung von numerischen Datentypen bei der Zuweisung erforderlich ist. Nur bei Zuweisung einer String-Variable mit numerisch darstellbarem Inhalt ist eine Konvertierung nötig (wegen 'OPTION STRICT ON').

Die mathematischen Funktionen in der Klasse MATH können von cDouble-Instanzen direkt verwendet werden. Falls man das Funktions-Ergebnis wieder auf eine cDouble-Instanz zuweist, wird beim Auftreten von IEEE-Sonderwerten der Overflow-Error ausgelöst.

Auch (z.B. mehrdimensionale) Arrays können aus Instanzen der Klasse 'cDouble' gebildet werden und sind im Code wie Double-Arrays verwendbar.

' =======================================================
' Klasse kapselt einen Double-Wert
' Fehler Overflow bei Wertebereichs-überschreitung 
' Verhalten imitiert integrierten VB-Datentyp
' =======================================================
' Mai 2007
' Manfred Bohn für VBARCHIV
 
Option Strict On
Option Explicit On
 
Public Class cDouble
 
  ' gekapselter Double-Wert
  Dim gDouble As Double
 
  ' zugelassene Werte-Limits:
  ' hier können auch bei Bedarf engere
  ' Beschränkungen vorgegeben werden
  Shared cMaxValue As Double = Double.MaxValue
  Shared cMinValue As Double = Double.MinValue
 
  ' relatives Epsilon für Wertvergleiche
  Shared cEpsilon As Double = 0.000001
  ' ================================================
  ' Konstruktoren
  ' ================================================
  Public Sub New()
    ' Standardkonstruktor 
    gDouble = 0.0
  End Sub
 
  Public Sub New(ByVal dbl As Double)
    ' Konstruktor mit Zuweisungsfunktion
    ' Initialisierung
    gDouble = 0.0
    Let_Value(dbl)
  End Sub
  ' ================================================
  ' Wertabfrage und Zuweisung (explizit)
  ' ================================================
  Public Sub Let_Value(ByVal dbl As Double)
    If Not CheckDouble(dbl) Then
      ' nur zugelassene Werte akzeptieren
      Throw New System.OverflowException
    Else
      ' Zuweisung
      gDouble = dbl
    End If
  End Sub
 
  Public Function Get_Value() As Double
    ' Wert-Abfrage
    Return gDouble
  End Function
  ' ====================================================
  ' klassenglobal vereinbarte Limits der Werteausprägung
  ' ====================================================
  Public Shared ReadOnly Property MinValue() As Double
    Get
      Return cMinValue
    End Get
  End Property
 
  Public Shared ReadOnly Property MaxValue() As Double
    Get
      Return cMaxValue
    End Get
  End Property
  ' ======================================================
  ' Limitüberprüfung (angewendet bei allen Parametern)
  ' ======================================================
  Private Shared Function CheckDouble(ByVal dbl As Double) As Boolean
    ' Wertebereich des Double prüfewn und 
    ' ggf. Fehler auslösen
 
    ' Durch diese Abfrage werden Infinity/Nan-Werte
    ' erkannt, ohne dass auf die entsprechenden 
    ' Double-Methoden 'IsNan', 'IsInfinity' 
    ' zurückgegriffen werden muss
    If dbl <= cMaxValue And _
      dbl >= cMinValue Then
      Return True
    Else
      Return False
    End If
  End Function
  Public Shared Widening Operator CType( _
    ByVal cdb As cDouble) As Double
 
    ' beliebige numerische Datentypen 
    ' können den Inhalt der Instanz von 
    ' cDouble aufnehmen, falls numerisch möglich
    ' ggf. nach impliziter Konvertierung
    Return cdb.Get_Value
  End Operator
 
  Public Shared Widening Operator CType( _
    ByVal dbl As Double) As cDouble
 
    ' beliebige numerische Werte können
    ' falls numerisch zulässig - in eine (neue) Instanz 
    ' von cDouble eingetragen werden (als Double-Wert)
    Dim erg As New cDouble(dbl)
    Return erg
  End Operator
  ' =========================================================
  ' Vergleichsoperatoren (Epsilon-Vergleich !!)
  ' =========================================================
  Public Shared Operator =( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As Boolean
 
    ' Epsilon-Vergleich von 2 Werten
    Return IsEqual(cdb1.Get_Value, cdb2.Get_Value)
  End Operator
 
  Public Shared Operator <>( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As Boolean
 
    Return (Not IsEqual(cdb1.Get_Value, cdb2.Get_Value))
  End Operator
 
  Public Shared Operator >( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As Boolean
 
    If Not IsEqual(cdb1.Get_Value, cdb2.Get_Value) Then
      Return cdb1.Get_Value > cdb2.Get_Value
    Else
      Return False
    End If
  End Operator
 
  Public Shared Operator <( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As Boolean
 
    If Not IsEqual(cdb1.Get_Value, cdb2.Get_Value) Then
      Return cdb1.Get_Value < cdb2.Get_Value
    Else
      Return False
    End If
  End Operator
 
  Public Shared Operator >=( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As Boolean
 
    If IsEqual(cdb1.Get_Value, cdb2.Get_Value) Then
      Return True
    Else
      Return cdb1 > cdb2
    End If
  End Operator
 
  Public Shared Operator <=( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As Boolean
 
    If IsEqual(cdb1.Get_Value, cdb2.Get_Value) Then
      Return True
    Else
      Return cdb1 < cdb2
    End If
  End Operator
  Private Shared Function IsEqual(ByVal dbl1 As Double, _
    ByVal dbl2 As Double) As Boolean
 
    ' allgemeine Hilfsfunktion: Vergleichsoperatoren 
    ' Epsilon-Vergleich von 2 Double-Werten
 
    Dim Min_Eps As Double = Double.Epsilon * 10
    Dim eps As Double = _
      cEpsilon * Math.Max(Math.Abs(dbl1), Math.Abs(dbl2))
 
    If eps < Min_eps Then eps = Min_Eps
    If dbl1 > eps And dbl2 < -eps Then
      Return False
    ElseIf dbl1 < -eps And dbl2 > eps Then
      Return False
    Else
      Return Math.Abs(dbl1 - dbl2) <= eps
    End If
  End Function
  ' ===========================================================
  ' Arithmetische Operatoren
  ' ===========================================================
  Public Shared Operator +( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As cDouble
 
    Dim erg As New cDouble
    erg.Let_Value(cdb1.Get_Value + cdb2.Get_Value)
    Return erg
  End Operator
 
  Public Shared Operator -( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As cDouble
 
    Dim erg As New cDouble
    erg.Let_Value(cdb1.Get_Value - cdb2.Get_Value)
    Return erg
  End Operator
 
  Public Shared Operator *( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As cDouble
 
    Dim erg As New cDouble
    erg.Let_Value(cdb1.Get_Value * cdb2.Get_Value)
    Return erg
  End Operator
 
  Public Shared Operator /( _
    ByVal cdb1 As cDouble, _
    ByVal cdb2 As cDouble) As cDouble
 
    Dim erg As New cDouble
    erg.Let_Value(cdb1.Get_Value / cdb2.Get_Value)
    Return erg
 
  End Operator
End Class
' =================================================================
' Ende der Klasse 'cDouble'
' =================================================================

Demonstrationsroutine

Public Sub cDouble_Demo()
  ' Routine zur Demonstration der Klasse 'cDouble'
 
  Dim lng1, lng2 As Long               ' Long
  Dim str_lng As String                ' String-Variable
  Dim dbl1, dbl2, dbl_erg As Double    ' Double
 
  Dim cdb1, cdb2, cdbl_erg As cDouble  ' cDouble-Instanzen
 
  Dim dbl_arr(,) As Double             ' Double-Array 
  Dim cdb_arr(,) As cDouble            ' cDouble-Array
 
  Dim i As Integer                     ' Loop
  Dim d1, d2 As Integer                ' Array-Loops
 
  ' Test-Durchläufe
  For i = 1 To 1000000
 
    ' 2 zufällige Double-Werte
    dbl1 = Random_Double()
    dbl2 = Random_Double()
    If dbl2 = 0 Then dbl2 = 1 ' 0 vermeiden
 
    ' Manchmal sind beide Werte gleich
    If i Mod 100 = 0 Then dbl2 = dbl1
 
    ' Zuweisung der Zufallswerte auf cDouble-Instanzen
    cdb1 = dbl1
    cdb2 = dbl2
 
    ' typreine Additionen und Ergebnisvergleich
    cdbl_erg = cdb1 + cdb2
    dbl_erg = dbl1 + dbl2
    If dbl_erg <> cdbl_erg Then Stop
 
    ' typgemischte Subtraktionen und Ergebnisvergleich
    cdbl_erg = cdb1 + dbl2
    dbl_erg = dbl1 + cdb2
    If dbl_erg <> cdbl_erg Then Stop
 
    ' typreine Multiplikation
    cdbl_erg = cdb1 * cdb2
    dbl_erg = dbl1 * dbl2
    If dbl_erg <> cdbl_erg Then Stop
 
    If Math.Abs(dbl2) > 0 Then
      ' typgemischte Divisionen und Ergebnisvergleich
      cdbl_erg = dbl1 / cdb2
      dbl_erg = cdb1 / dbl2
      If dbl_erg <> cdbl_erg Then Stop
    End If
 
    ' Vergleichsoperatoren:
    ' Double-Vergleich muss cDouble-Vergleich entsprechen 
    If (dbl1 > dbl2) <> (cdb1 > cdb2) Then Stop
    If (dbl1 < dbl2) <> (cdb1 < cdb2) Then Stop
 
    If (dbl1 >= dbl2) <> (cdb1 >= cdb2) Then Stop
    If (dbl1 <= dbl2) <> (cdb1 <= cdb2) Then Stop
 
    If (dbl1 <> dbl2) <> (cdb1 <> cdb2) Then Stop
    If (dbl1 = dbl2) <> (cdb1 = cdb2) Then Stop
 
    ' Verwendung von MATH-Funktionen
    If Math.Sqrt(Math.Abs(dbl1)) <> _
      Math.Sqrt(Math.Abs(cdb1)) Then Stop
    If Math.Pow(Math.Abs(dbl1), 0.55) <> _
      Math.Pow(Math.Abs(cdb1), 0.55) Then Stop
    If Math.Round(dbl1, 5) <> _
      Math.Round(cdb1, 5) Then Stop
    If Math.Truncate(dbl1) <> _
      Math.Truncate(cdb1) Then Stop
 
    ' 2 zufällige Long-Werte
    lng1 = CLng(10000 * Rnd())
    lng2 = CLng(1000000 * Rnd())
    If lng2 = 0 Then lng2 = 1 ' 0 vermeiden
 
    ' Umwandlung in einen String
    str_lng = CStr(lng1)
 
    ' Zuweisung eines numerischen Strings auf cDouble
    cdb1 = CDbl(str_lng)
 
    ' Zuweisung eines Long-Wertes auf cDouble
    cdb2 = lng2
 
    ' Ergebnisvergleich nach typgemischter Addition 
    If lng1 + cdb2 <> cdb2 + lng1 Then Stop
    If lng1 / cdb2 <> cdb1 / lng2 Then Stop
 
    ' cDouble-Array
    ReDim cdb_arr(10, 20)
    ' Double-Array
    ReDim dbl_arr(UBound(cdb_arr, 1), UBound(cdb_arr, 2))
 
    For d1 = 0 To UBound(cdb_arr, 1)
      For d2 = 0 To UBound(cdb_arr, 2)
        ' Arrays füllen
        cdb_arr(d1, d2) = Rnd()
        dbl_arr(d1, d2) = cdb_arr(d1, d2)
      Next d2
    Next d1
 
    cdb1 = 0 : cdb2 = 0 ' für Summation
    For d1 = 0 To UBound(cdb_arr, 1)
      For d2 = 0 To UBound(cdb_arr, 2)
        ' Inhalt der Arrays vergleichen
        If cdb_arr(d1, d2) <> dbl_arr(d1, d2) Then Stop
        ' Summation der Felder in cDouble-Instanzen
        cdb1 += cdb_arr(d1, d2)
        cdb2 += dbl_arr(d1, d2)
      Next d2
    Next d1
 
    ' Vergleich der Feld-Summen beider Arrays
    If cdb1 <> cdb2 Then Stop
 
    ' nächster Durchlauf
  Next i
End Sub
Public Function Random_Double() As Double
  ' zufälliger Double-Wert im Bereich 
  ' -1E30 bis +1E30
 
  Dim x As Double = Rnd() * 1.0E+30
  If Rnd() > 0.5 Then x = -x
  Return x
End Function



Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
 
Copyright ©2000-2024 vb@rchiv Dieter OtterAlle Rechte vorbehalten.


Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.