Leider DateTime
ist ein weird type für Marshalling (oder zumindest hat es ein ziemlich unerwartetes überraschendes Verhalten.)
Vor allem, weil es einistStruktur (und dies macht es nicht-blitable und mit allen consequences des Gehäuses) mit nur einem einzigen long
Feld.
Sie mögen denken, zu Wrap es in einem blitfähig struct (hier nichts Neues, es ist der gemeinsame Weg nicht blitfähige Typs Marschall):
public struct BlittableDateTime
{
private BlittableDateTime(long ticks)
{
_ticks = ticks;
}
public static implicit operator BlittableDateTime(DateTime value)
{
return new BlittableDateTime(value.Ticks);
}
public static implicit operator DateTime(BlittableDateTime value)
{
return new DateTime(value._ticks);
}
private readonly long _ticks;
}
So weit so gut, Sie vielleicht denken, . Allerdings sind wir Umwandlung eine DateTime
(Anzahl von 100 ns Ticks von 1/1/0001) zu einem 8-Byte-Integer-Wert ohne jeden äquivalenten Typ in unmanaged Welt. In nicht verwalteten Welt können Sie haben: time_t
, FILETIME
, SYSTEMTIME
, DATE
und (viele) andere, aber none of them exactly matches granularity and range von .NET DateTime
. Noch mehr ärgerlich es ist nicht wirklich ein rohlong long
Wert, da einige Bits eine besondere Bedeutung haben, aus dem Quellcode:
Bits 63-64: Ein Vier-Zustands-Wert, der das Datetimekind Wert des Datums beschreibt Zeit ...
Sie benötigen einen Umwandlung, in diesem Beispiel gehe ich mit FILETIME
:
public static implicit operator BlittableDateTime(DateTime value)
{
return new BlittableDateTime(value.ToFileTime());
}
public static implicit operator DateTime(BlittableDateTime value)
{
return DateTime.FromFileTime(value._ticks);
}
Bearbeiten: wie man es benutzt? Wir definierten zwei implizite Operatoren dann Conversions zu/von DateTime
automatische sind, brauchen Sie nicht direkt FILETIME
Struktur in verwaltetem Code verwalten (beachten Sie auch, dass Konstruktor privat ist, alle Konvertierungen durch definierten Operatoren gehen werden):
BlittableDateTime time1 = DateTime.UtcNow;
DateTime time2 = time1;
Allerdings haben wir für diesen Typ keine Vergleichsoperatoren definiert.Wenn Sie das nicht tun es oft zwei Alternativen, die Sie haben, erste ist Gießen:
if ((DateTime)time1 == time2) {
// Do something...
}
Alternativ können Sie Value
Eigenschaft hinzufügen, die DateTime
zurückgibt (zu Nullable<T>
Nutzung zu imitieren):
public DateTime Value
{
get { return (DateTime)this; }
}
Gebraucht wie folgt aus:
if (time1.Value == time2) {
// Do something...
}
Noch eine n Hinweise zu Conversions Beachten Sie, dass nicht jede Konvertierung möglich ist und - in diesem Fall - FILETIME
einen anderen Bereich hat. FILETIME
beginnt am 1/1/1601 und mit einer Granularität von 100 ns erstreckt es sich +/- 30.000 Jahre (mehr oder weniger), weil es negativ sein kann. DateTime
beginnt am 1.1.0001 und verwendet effektiv 62 Bits von Informationen (2 Ticks) aber Maximalwert ist der 31. Dezember 9999. Ein weiteres Problem : current implementation nicht negative Werte unterstützen, wenn von der Rückseite FILETIME
dann effektiv nutzbare Bereich Umwandeln ist zwischen dem 1. Januar 1601 (mindestens positivFILETIME
) und 31.12.9999 (maximal DateTime
und DATE
Wert).
Bei der Arbeit mit Daten nicht vergessen, dass sie (fast) immer mit einem Kalender verbunden sind und einige Kalender können unterschiedliche Grenzen haben: zum Beispiel beginnt Taiwan Kalender um 1/1/0001 (das ist 1/1/1912 im Gregorianischen Kalender) und Um Al Qura Kalender endet am 29.12.1450 (5/13/2029 im Gregorianischen Kalender).
Im Grunde genommen erstelle ich eine neue Struktur mit den beiden obigen Beispielen kombiniert (mit dem zweiten, um den Inhalt des ersten zu überschreiben). Dann definiere ich 'LastWrite' und' LastRead' als 'BlittableDateTime' korrekt? Als Beispiel kann 'public BlittableDateTime LastWrite;'. Dann muss ich nichts für 'BlittableDateTime' Typen marschieren oder? –
Genau. Ändere FILETIME zu dem, was am besten zu deiner nicht verwalteten Verwendung passt –
Das sollte gut funktionieren, danke! Ein Problem, auf das ich stoße ... Wenn ich versuche, etwas wie "BlittableDateTime test = BlittableDateTime (DateTime.Now.ToFileTime)" zu machen; wird es nicht funktionieren. Können Sie Ihre Antwort vielleicht aktualisieren, um etwas außerhalb der Struktur zu verwenden? Vielleicht nach dem Definieren der Struktur, erstellen Sie ein Objekt des Strukturtyps und vergleichen Sie es dann mit einem anderen Objekt des gleichen Typs? Beispiel: 'BlittableDateTime test = BlittableDateTime (DateTime.Now.ToFileTime);' dann 'BlittableDateTime test2 = BlitableDateTime (DateTime.Now.ToFileTime);' dann 'if (test! = Test2) {// tue arbeiten}' –