Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Gilt für:SQL Server
Beim Codieren ihrer benutzerdefinierten Typdefinition (USER-Defined Type, UDT) müssen Sie verschiedene Features implementieren, je nachdem, ob Sie udT als Klasse oder Struktur implementieren, sowie die von Ihnen ausgewählten Format- und Serialisierungsoptionen.
Das Beispiel in diesem Abschnitt veranschaulicht die Implementierung eines Point UDT als struct (oder Structure in Visual Basic). Die Point UDT besteht aus X- und Y-Koordinaten, die als Eigenschaftsprozeduren implementiert werden.
Beim Definieren eines UDTs sind die folgenden Namespaces erforderlich:
using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
Der Microsoft.SqlServer.Server-Namespace enthält die Objekte, die für verschiedene Attribute Ihres UDT erforderlich sind, und der System.Data.SqlTypes Namespace enthält die Klassen, die sql Server native Datentypen darstellen, die für die Assembly verfügbar sind. Möglicherweise gibt es andere Namespaces, die Ihre Assembly benötigt, um ordnungsgemäß zu funktionieren. Die Point UDT verwendet auch den System.Text Namespace zum Arbeiten mit Zeichenfolgen.
Hinweis
Visual C++-Datenbankobjekte, z. B. UDTs, die mit /clr:pure kompiliert werden, werden für die Ausführung nicht unterstützt.
Angeben von Attributen
Attribute bestimmen, wie die Serialisierung verwendet wird, um die Speicherdarstellung von UDTs zu erstellen und um UDTs durch Werte an den Client zu übertragen.
Die Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute ist erforderlich. Das attribut Serializable ist optional. Sie können auch die Microsoft.SqlServer.Server.SqlFacetAttribute angeben, um Informationen zum Rückgabetyp eines UDT bereitzustellen. Weitere Informationen finden Sie unter CLR-Integration: benutzerdefinierte Attribute für CLR-Routinen.
Point UDT-Attribute
Die Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute legt das Speicherformat für das Point UDT auf Nativefest.
IsByteOrdered wird auf truefestgelegt, wodurch sichergestellt wird, dass die Ergebnisse von Vergleichen in SQL Server identisch sind, als ob derselbe Vergleich im verwalteten Code stattgefunden hat. Das UDT implementiert die System.Data.SqlTypes.INullable Schnittstelle, um udT null zu erkennen.
Das folgende Codefragment zeigt die Attribute für das Point UDT.
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native,
IsByteOrdered=true)]
public struct Point : INullable { ... }
Implementieren der Nullierbarkeit
Zusätzlich zum ordnungsgemäßen Angeben der Attribute für die Assemblys muss der UDT auch die NULL-Zulässigkeit unterstützen. UDTs, die in SQL Server geladen werden, sind nullfähig, damit udT jedoch einen Nullwert erkennt, muss die UDT die System.Data.SqlTypes.INullable Schnittstelle implementieren.
Sie müssen eine Eigenschaft namens IsNullerstellen, die erforderlich ist, um zu bestimmen, ob ein Wert null aus dem CLR-Code ist. Wenn SQL Server eine NULL-Instanz eines UDT findet, wird der UDT mithilfe normaler Nullbehandlungsmethoden beibehalten. Der Server verschwendet keine Zeit beim Serialisieren oder Deserialisieren des UDT, wenn er nicht erforderlich ist, und es verschwendet keinen Speicherplatz, um einen NULL-UDT zu speichern. Diese Überprüfung auf NULL-Werte wird jedes Mal ausgeführt, wenn ein UDT von der CLR übernommen wird, was bedeutet, dass die Verwendung des Transact-SQL IS NULL-Konstrukts zur Überprüfung auf NULL-UDTs immer funktionieren sollte. Die IsNull-Eigenschaft wird auch vom Server verwendet, um zu testen, ob eine Instanz null ist. Sobald der Server bestimmt, dass der UDT NULL ist, kann er seine systemeigene NULL-Behandlung verwenden.
Die get()-Methode von IsNull ist in keiner Weise speziell. Wenn eine Point Variable @pNullist, wird @p.IsNull standardmäßig als NULLausgewertet, nicht 1. Dies liegt daran, dass das SqlMethod(OnNullCall)-Attribut der IsNull get()-Methode standardmäßig auf "false" festgelegt ist. Da das Objekt Nullist, wird die Methode nicht aufgerufen, und ein Standardwert von "NULL" wird zurückgegeben, wenn die Eigenschaft angefordert wird, das Objekt nicht deserialisiert wird.
Beispiel
Im folgenden Beispiel ist die is_Null-Variable privat und enthält für die Instanz des UDT den Status NULL. Im Code muss ein entsprechender Wert für is_Null verwaltet werden. Das UDT muss auch über eine statische Eigenschaft mit dem Namen Null verfügen, die eine NULL-Wertinstanz des UDT zurückgibt. Dadurch kann der UDT einen NULL-Wert zurückgeben, wenn die Instanz auch in der Datenbank tatsächlich NULL ist.
private bool is_Null;
public bool IsNull
{
get
{
return (is_Null);
}
}
public static Point Null
{
get
{
Point pt = new Point();
pt.is_Null = true;
return pt;
}
}
IS NULL und IsNull
Erwägen Sie eine Tabelle, die das Schema Points(id int, location Point)enthält, wobei Point ein CLR-UDT ist, und die folgenden Abfragen:
Abfrage 1:
SELECT ID FROM Points WHERE NOT (location IS NULL); -- Or, WHERE location IS NOT NULL;Abfrage 2:
SELECT ID FROM Points WHERE location.IsNull = 0;
Beide Abfragen geben die IDs von Punkten mit Nicht-NULL-Speicherorten zurück. In Abfrage 1 wird die normale NULL-Behandlung verwendet, und dort ist keine Deserialisierung von UDTs erforderlich. Abfrage 2 muss dagegen jedes Nicht-Null-Objekt deserialisieren und den CLR aufrufen, um den Wert der IsNull-Eigenschaft abzurufen. Klar, die Verwendung von IS NULL zeigt eine bessere Leistung und es sollte niemals ein Grund geben, die IsNull Eigenschaft eines UDT aus Transact-SQL Code zu lesen.
Was ist also die Verwendung der IsNull-Eigenschaft? Zunächst ist es erforderlich, um zu bestimmen, ob ein Wert im CLR-Code null ist. Zweitens benötigt der Server eine Möglichkeit, zu testen, ob eine Instanz null ist, sodass diese Eigenschaft vom Server verwendet wird. Nachdem sie als NULL festgelegt wurde, kann sie die systemeigene Nullbehandlung verwenden, um sie zu behandeln.
Implementieren der Analysemethode
Die methoden Parse und ToString ermöglichen Konvertierungen in und aus Zeichenfolgendarstellungen des UDT. Mit der Parse-Methode kann eine Zeichenfolge in ein UDT konvertiert werden. Sie muss als static (oder Shared in Visual Basic) deklariert werden und einen Parameter vom Typ System.Data.SqlTypes.SqlStringverwenden.
Der folgende Code implementiert die Parse-Methode für die Point UDT, die die X- und Y-Koordinaten trennt. Die Parse-Methode weist ein einzelnes Argument vom Typ System.Data.SqlTypes.SqlStringauf und geht davon aus, dass X- und Y-Werte als durch Trennzeichen getrennte Zeichenfolge angegeben werden. Wenn Sie das attribut Microsoft.SqlServer.Server.SqlMethodAttribute.OnNullCall auf false festlegen, wird verhindert, dass die Parse-Methode von einer Nullinstanz von Point aufgerufen wird.
[SqlMethod(OnNullCall = false)]
public static Point Parse(SqlString s)
{
if (s.IsNull)
return Null;
// Parse input string to separate out points.
Point pt = new Point();
string[] xy = s.Value.Split(",".ToCharArray());
pt.X = Int32.Parse(xy[0]);
pt.Y = Int32.Parse(xy[1]);
return pt;
}
Implementieren der ToString-Methode
Die ToString-Methode konvertiert die Point UDT in einen Zeichenfolgenwert. In diesem Fall wird die Zeichenfolge "NULL" für eine Null-Instanz des typs Point zurückgegeben. Die ToString-Methode kehrt die Parse-Methode um, indem ein System.Text.StringBuilder verwendet wird, um ein durch Trennzeichen getrenntes System.String zurückzugeben, das aus den X- und Y-Koordinatenwerten besteht. Da InvokeIfReceiverIsNull standardmäßig auf "false" festgelegt ist, ist die Überprüfung auf eine NULL-Instanz von Point nicht erforderlich.
private Int32 _x;
private Int32 _y;
public override string ToString()
{
if (this.IsNull)
return "NULL";
else
{
StringBuilder builder = new StringBuilder();
builder.Append(_x);
builder.Append(",");
builder.Append(_y);
return builder.ToString();
}
}
Verfügbarmachen von UDT-Eigenschaften
Die Point UDT macht X- und Y-Koordinaten verfügbar, die als öffentliche Lese-/Schreibeigenschaften vom Typ System.Int32implementiert werden.
public Int32 X
{
get
{
return this._x;
}
set
{
_x = value;
}
}
public Int32 Y
{
get
{
return this._y;
}
set
{
_y = value;
}
}
Überprüfen von UDT-Werten
Beim Arbeiten mit UDT-Daten konvertiert SQL Server Datenbank-Engine binäre Werte automatisch in UDT-Werte. Im Rahmen dieses Konvertierungsprozesses muss überprüft werden, ob sich die Werte für das Serialisierungsformat des Typs eignen, und sichergestellt werden, dass die Werte ordnungsgemäß deserialisiert werden können. Dadurch wird sichergestellt, dass der Wert wieder in binäre Form konvertiert werden kann. Bei UDTs, deren Sortierreihenfolge eine Bytereihenfolge ist, wird dadurch auch sichergestellt, dass der resultierende Binärwert dem ursprünglichen Binärwert entspricht. So wird verhindert, dass ungültige Werte in der Datenbank persistent gespeichert werden. In einigen Fällen ist diese Überprüfung möglicherweise unzureichend. Möglicherweise ist eine zusätzliche Überprüfung erforderlich, wenn UDT-Werte in einer erwarteten Domäne oder einem erwarteten Bereich enthalten sein müssen. Ein UDT beispielsweise, der ein Datum implementiert, kann erfordern, dass der Wert für den Tag eine positive Zahl ist, die in einem bestimmten zulässigen Wertebereich liegt.
Mit der Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute.ValidationMethodName-Eigenschaft des Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute können Sie den Namen einer Überprüfungsmethode angeben, die vom Server ausgeführt wird, wenn Daten einem UDT zugewiesen oder in ein UDT konvertiert werden.
ValidationMethodName wird auch während der Ausführung des bcp Hilfsprogramms, BULK INSERT, DBCC CHECKDB, DBCC CHECKFILEGROUP, DBCC CHECKTABLE, verteilte Abfrage und TDS-Remoteprozeduraufruf (Remote Data Stream, TDS) remote procedure call (RPC) aufgerufen. Der Standardwert für ValidationMethodName ist null, was angibt, dass keine Überprüfungsmethode vorhanden ist.
Beispiel
Das folgende Codefragment zeigt die Deklaration für die klasse Point, die einen ValidationMethodName von ValidatePointangibt.
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native,
IsByteOrdered=true,
ValidationMethodName = "ValidatePoint")]
public struct Point : INullable { ... }
Wenn eine Validierungsmethode angegeben wird, muss diese eine Signatur aufweisen, die etwa folgendem Codefragment entspricht:
private bool ValidationFunction()
{
if (validation logic here)
{
return true;
}
else
{
return false;
}
}
Die Validierungsmethode kann einen beliebigen Bereich aufweisen und sollte true zurückgeben, wenn der Wert gültig ist, und andernfalls false. Wenn die Methode false zurückgibt oder eine Ausnahme auslöst, wird der Wert als ungültig behandelt und ein Fehler ausgelöst.
Im folgenden Beispiel lässt der Code nur Werte von Null oder höher die X- und Y-Koordinaten zu.
private bool ValidatePoint()
{
if ((_x >= 0) && (_y >= 0))
{
return true;
}
else
{
return false;
}
}
Einschränkungen der Validierungsmethode
Der Server ruft die Überprüfungsmethode auf, wenn der Server Konvertierungen ausführt, nicht, wenn Daten eingefügt werden, indem einzelne Eigenschaften festgelegt werden oder wenn Daten mithilfe einer Transact-SQL INSERT-Anweisung eingefügt werden.
Sie müssen die Überprüfungsmethode explizit von Eigenschaftensatzern und der Parse-Methode aufrufen, wenn die Überprüfungsmethode in allen Situationen ausgeführt werden soll. Dies ist keine Anforderung, und in einigen Fällen ist dies möglicherweise nicht einmal wünschenswert.
Beispiel für die Analyseüberprüfung
Um sicherzustellen, dass die ValidatePoint-Methode in der Point-Klasse aufgerufen wird, müssen Sie sie aus der Parse-Methode und den Eigenschaftenprozeduren aufrufen, die die X- und Y-Koordinatenwerte festlegen. Das folgende Codefragment zeigt, wie die ValidatePoint Validierungsmethode aus der Parse-Funktion aufgerufen wird.
[SqlMethod(OnNullCall = false)]
public static Point Parse(SqlString s)
{
if (s.IsNull)
return Null;
// Parse input string to separate out points.
Point pt = new Point();
string[] xy = s.Value.Split(",".ToCharArray());
pt.X = Int32.Parse(xy[0]);
pt.Y = Int32.Parse(xy[1]);
// Call ValidatePoint to enforce validation
// for string conversions.
if (!pt.ValidatePoint())
throw new ArgumentException("Invalid XY coordinate values.");
return pt;
}
Beispiel für die Eigenschaftsüberprüfung
Das folgende Codefragment zeigt, wie die ValidatePoint Validierungsmethode aus den Eigenschaftenprozeduren aufgerufen wird, die die X- und Y-Koordinaten festlegen.
public Int32 X
{
get
{
return this._x;
}
// Call ValidatePoint to ensure valid range of Point values.
set
{
Int32 temp = _x;
_x = value;
if (!ValidatePoint())
{
_x = temp;
throw new ArgumentException("Invalid X coordinate value.");
}
}
}
public Int32 Y
{
get
{
return this._y;
}
set
{
Int32 temp = _y;
_y = value;
if (!ValidatePoint())
{
_y = temp;
throw new ArgumentException("Invalid Y coordinate value.");
}
}
}
Code UDT-Methoden
Bei Codieren von UDT-Methoden müssen Sie berücksichtigen, ob sich der verwendete Algorithmus möglicherweise im Lauf der Zeit ändern könnte. Wenn ja, sollten Sie in Erwägung ziehen, eine separate Klasse für die methoden zu erstellen, die Ihre UDT verwendet. Wenn sich der Algorithmus ändert, können Sie die Klasse mit dem neuen Code neu kompilieren und die Assembly in SQL Server laden, ohne dass sich dies auf das UDT auswirkt. In vielen Fällen können UDTs mithilfe der Transact-SQL ALTER ASSEMBLY-Anweisung neu geladen werden, dies kann jedoch möglicherweise Probleme mit vorhandenen Daten verursachen. Beispielsweise verwendet das in der AdventureWorks2022 Beispieldatenbank enthaltene Currency UDT eine ConvertCurrency Funktion zum Konvertieren von Währungswerten, die in einer separaten Klasse implementiert wird. Es ist möglich, dass Sich Konvertierungsalgorithmen in Zukunft auf unvorhersehbare Weise ändern oder dass neue Funktionen erforderlich sind. Das Trennen der ConvertCurrency-Funktion von der Currency UDT-Implementierung bietet größere Flexibilität bei der Planung zukünftiger Änderungen.
Beispiel
Die Point Klasse enthält drei einfache Methoden zum Berechnen der Entfernung: Distance, DistanceFromund DistanceFromXY. Jeder gibt einen double zurück, der den Abstand zwischen Point und Null berechnet, den Abstand zwischen einem angegebenen Punkt und Pointsowie den Abstand zwischen den angegebenen X- und Y-Koordinaten zu Point.
Distance und DistanceFrom jedem Aufruf DistanceFromXYund veranschaulichen, wie für jede Methode unterschiedliche Argumente verwendet werden.
// Distance from 0 to Point.
[SqlMethod(OnNullCall = false)]
public Double Distance()
{
return DistanceFromXY(0, 0);
}
// Distance from Point to the specified point.
[SqlMethod(OnNullCall = false)]
public Double DistanceFrom(Point pFrom)
{
return DistanceFromXY(pFrom.X, pFrom.Y);
}
// Distance from Point to the specified x and y values.
[SqlMethod(OnNullCall = false)]
public Double DistanceFromXY(Int32 iX, Int32 iY)
{
return Math.Sqrt(Math.Pow(iX - _x, 2.0) + Math.Pow(iY - _y, 2.0));
}
Verwenden von SqlMethod-Attributen
Die Microsoft.SqlServer.Server.SqlMethodAttribute-Klasse stellt benutzerdefinierte Attribute bereit, die zum Markieren von Methodendefinitionen verwendet werden können, um den Determinismus, das Verhalten des Nullaufrufs anzugeben und anzugeben, ob es sich bei einer Methode um einen Mutator handelt. Bei diesen Eigenschaften werden die Standardwerte vorausgesetzt, und das benutzerdefinierte Attribut wird nur verwendet, wenn ein anderer Wert als der Standardwert erforderlich ist.
Hinweis
Die SqlMethodAttribute Klasse erbt von der SqlFunctionAttribute Klasse, sodass SqlMethodAttribute die Felder FillRowMethodName und TableDefinition von SqlFunctionAttributeerbt. Dies bedeutet, dass es möglich ist, eine Tabellenwertmethode zu schreiben, was nicht der Fall ist. Die Methode kompiliert und die Assembly wird bereitgestellt, aber zur Laufzeit wird ein Fehler über den IEnumerable Rückgabetyp ausgelöst, wobei die folgende Meldung angezeigt wird: "Methode, Eigenschaft oder Feld <name> in der Klasse <class> in assembly <assembly> hat ungültigen Rückgabetyp."
Die folgende Tabelle beschreibt einige der relevanten Microsoft.SqlServer.Server.SqlMethodAttribute Eigenschaften, die in UDT-Methoden verwendet werden können, und listet ihre Standardwerte auf.
| Eigentum | Beschreibung |
|---|---|
DataAccess |
Gibt an, ob die Funktion Zugriff auf in der lokalen Instanz von SQL Server gespeicherte Benutzerdaten einschließt. Der Standardwert ist DataAccessKind.None. |
IsDeterministic |
Gibt an, ob die Funktion bei denselben Eingabewerten und demselben Datenbankzustand auch immer dieselben Ausgabewerte erzeugt. Der Standardwert ist false. |
IsMutator |
Gibt an, ob die Methode eine Statusänderung in der UDT-Instanz verursacht. Der Standardwert ist false. |
IsPrecise |
Gibt an, ob die Funktion ungenaue Berechnungen beinhaltet, z. B. Gleitkommaoperationen. Der Standardwert ist false. |
OnNullCall |
Gibt an, ob die Methode aufgerufen wird, wenn als Eingabeargumente NULL-Verweise angegeben werden. Der Standardwert ist true. |
Beispiel
Mit der Microsoft.SqlServer.Server.SqlMethodAttribute.IsMutator-Eigenschaft können Sie eine Methode markieren, die eine Änderung des Zustands einer Instanz eines UDT zulässt. Transact-SQL ermöglicht es Ihnen nicht, zwei UDT-Eigenschaften in der SET-Klausel einer UPDATE-Anweisung festzulegen. Sie können jedoch eine Methode als Mutator markieren, die zwei Elemente ändert.
Hinweis
Mutatormethoden sind in Abfragen nicht zulässig. Sie können nur in Zuweisungsanweisungen oder Datenänderungsanweisungen aufgerufen werden. Wenn eine als Mutator gekennzeichnete Methode nicht void zurückgibt (oder kein Sub in Visual Basic ist), schlägt CREATE TYPE mit einem Fehler fehl.
Die folgende Anweisung geht davon aus, dass eine Triangles UDT vorhanden ist, die eine Rotate-Methode aufweist. Die folgende Transact-SQL Update-Anweisung ruft die Rotate Methode auf:
UPDATE Triangles
SET t.RotateY(0.6)
WHERE id = 5;
Die Rotate-Methode ist mit der SqlMethod Attributeinstellung IsMutator auf true versehen, sodass SQL Server die Methode als Mutatormethode markieren kann. Der Code legt außerdem OnNullCall auf falsefest, was an den Server angibt, dass die Methode einen Nullverweis (Nothing in Visual Basic) zurückgibt, wenn einer der Eingabeparameter NULL-Verweise ist.
[SqlMethod(IsMutator = true, OnNullCall = false)]
public void Rotate(double anglex, double angley, double anglez)
{
RotateX(anglex);
RotateY(angley);
RotateZ(anglez);
}
Implementieren eines UDT mit einem benutzerdefinierten Format
Wenn Sie ein UDT mit einem benutzerdefinierten Format implementieren, müssen Sie Read und Write Methoden implementieren, die die Microsoft.SqlServer.Server.IBinarySerialize Schnittstelle implementieren, um UDT-Daten serialisieren und deserialisieren zu können. Sie müssen auch die MaxByteSize-Eigenschaft des Microsoft.SqlServer.Server.SqlUserDefinedTypeAttributeangeben.
Die Währung UDT
Die Currency UDT ist in den CLR-Beispielen enthalten, die mit SQL Server installiert werden können.
Die Currency UDT unterstützt die Abwicklung von Geldbeträgen im Währungssystem einer bestimmten Kultur. Sie müssen zwei Felder definieren: eine string für CultureInfo, die angibt, wer die Währung ausgegeben hat ( z. B.en-us), und eine decimal für CurrencyValue, den Betrag des Geldes.
Obwohl sie nicht vom Server zum Ausführen von Vergleichen verwendet wird, implementiert das Currency UDT die System.IComparable Schnittstelle, die eine einzelne Methode verfügbar macht, System.IComparable.CompareTo. Dies wird auf clientseitiger Seite in Situationen verwendet, in denen es wünschenswert ist, Währungswerte innerhalb der Kulturen genau zu vergleichen oder zu ordnen.
Im Code, der in der CLR ausgeführt wird, wird die Länderangabe getrennt vom Währungswert verglichen. Bei Transact-SQL-Code bestimmen die folgenden Aktionen den Vergleich:
Legen Sie das attribut
IsByteOrderedauf "true" fest, das SQL Server angibt, die permanente binäre Darstellung auf dem Datenträger für Vergleiche zu verwenden.Verwenden Sie die
Write-Methode für dieCurrencyUDT, um zu bestimmen, wie das UDT auf dem Datenträger beibehalten wird und wie UDT-Werte für Transact-SQL Vorgänge verglichen und sortiert werden.Speichern Sie die
CurrencyUDT im folgenden Binärformat:Speichern Sie die Länderangabe als UTF-16-codierte Zeichenfolge für die Bytes 0 bis 19, wobei die Zeichenfolge rechts mit NULL-Zeichen aufgefüllt werden soll.
Verwenden Sie Bytes 20 und nachfolgende Bytes zum Speichern des Dezimalwerts der Währungsbetrags.
Der Zweck des Abstands besteht darin, sicherzustellen, dass die Kultur vollständig vom Währungswert getrennt ist. Wenn ein UDT mit einem anderen im Transact-SQL-Code verglichen wird, werden Kulturbytes mit Kulturbytes verglichen, und Währungsbytewerte werden mit Währungsbytewerten verglichen.
Währungsattribute
Die Currency UDT wird mit den folgenden Attributen definiert.
[Serializable]
[SqlUserDefinedType(Format.UserDefined,
IsByteOrdered = true, MaxByteSize = 32)]
[CLSCompliant(false)]
public struct Currency : INullable, IComparable, IBinarySerialize
{ ... }
Erstellen von Lese- und Schreibmethoden mit ibinaryserialize
Wenn Sie UserDefined Serialisierungsformat auswählen, müssen Sie auch die IBinarySerialize Schnittstelle implementieren und eigene Read- und Write Methoden erstellen. Die folgenden Verfahren aus dem Currency UDT verwenden das System.IO.BinaryReader und System.IO.BinaryWriter zum Lesen und Schreiben in udT.
// IBinarySerialize methods
// The binary layout is as follow:
// Bytes 0 - 19:Culture name, padded to the right
// with null characters, UTF-16 encoded
// Bytes 20+:Decimal value of money
// If the culture name is empty, the currency is null.
public void Write(System.IO.BinaryWriter w)
{
if (this.IsNull)
{
w.Write(nullMarker);
w.Write((decimal)0);
return;
}
if (cultureName.Length > cultureNameMaxSize)
{
throw new ApplicationException(string.Format(
CultureInfo.InvariantCulture,
"{0} is an invalid culture name for currency as it is too long.",
cultureNameMaxSize));
}
String paddedName = cultureName.PadRight(cultureNameMaxSize, '\0');
for (int i = 0; i < cultureNameMaxSize; i++)
{
w.Write(paddedName[i]);
}
// Normalize decimal value to two places
currencyValue = Decimal.Floor(currencyValue * 100) / 100;
w.Write(currencyValue);
}
public void Read(System.IO.BinaryReader r)
{
char[] name = r.ReadChars(cultureNameMaxSize);
int stringEnd = Array.IndexOf(name, '\0');
if (stringEnd == 0)
{
cultureName = null;
return;
}
cultureName = new String(name, 0, stringEnd);
currencyValue = r.ReadDecimal();
}