定义精确大小的内存结构
Defining precise sized memory structures
我正在做一些内存共享,我将在内存共享区域中使用以下结构...
[StructLayout(LayoutKind.Sequential)]
public struct MySharedMemory
{
//Bools
public bool Flag1;
public bool Flag2;
public bool Flag3;
//DateTimes
public DateTime LastWrite;
public DateTime LastRead;
//Longs
public long SrcSize;
//Strings that are a max of 250 characters
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 250)]
public string SrcFile;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 250)]
public string DestFile;
//Ints
public int Count;
//An array of strings that are a max of 100 characters
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100, ArraySubType = UnmanagedType.Struct)]
public FileInfo[] FilesToUpdate;
}
我知道上面的所有定义都是正确的,但 DataTime 除外。我只是添加了那些,但我不确定它们是否是固定大小,或者我需要定义一些特殊的东西,就像我为字符串所做的那样。我的问题是,除了数组和字符串之外,还有没有固定大小的任何类型(特别是我的 DateTime 定义是否正确)?
我会使用 long
,并且只使用 属性 将其公开为 DateTime
:
public struct YourStruct
{
...
private long myTimeAsTicks;
public DateTime MyTime
{
get { return new DateTime(myTimeAsTicks); }
set { myTimeAsTicks = value.Ticks; }
}
...
}
获取结构的实际大小实际上有点棘手,请参阅
不幸的是 DateTime
是一个 weird type 用于封送处理(或者,至少,它有一个非常意外的令人惊讶的行为。)
首先,因为它是一个 Auto
结构(这使得它不可 blittable 并且所有 consequences 大小写)只有一个 long
字段。
你可能会想 wrap 它在一个 blittable 结构中(这里没有什么新鲜事,这是编组非 blittable 类型的 常用方法 ):
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;
}
到目前为止还不错,您可能会想。然而,我们正在转换一个DateTime
(从1/1/0001开始的100 ns滴答数)到一个8字节整数值,在中没有任何等效类型不受管理的 世界。在不受管理的世界中,您可能有:time_t
、FILETIME
、SYSTEMTIME
、DATE
和(许多)其他但none of them exactly matches granularity and range 的 .NET DateTime
。更 annoying 它实际上不是 raw long long
值,因为某些位具有特殊含义,来自源代码:
Bits 63-64: A four-state value that describes the DateTimeKind value of the date time...
你需要一个转换,在这个例子中我选择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);
}
编辑:如何使用?我们定义了两个隐式运算符然后转换 to/from DateTime
是 自动 ,你不需要在托管代码中直接管理 FILETIME
结构(还要注意构造函数是私有的,所有转换都通过定义的运算符进行):
BlittableDateTime time1 = DateTime.UtcNow;
DateTime time2 = time1;
但是我们没有为此类型定义任何比较运算符。如果你不经常这样做,你有两个选择,第一个是铸造:
if ((DateTime)time1 == time2) {
// Do something...
}
或者你可以添加 Value
属性 其中 returns DateTime
(模仿 Nullable<T>
用法):
public DateTime Value
{
get { return (DateTime)this; }
}
这样使用:
if (time1.Value == time2) {
// Do something...
}
关于转换的更多说明。请注意,并非所有转换都是可能的,并且 - 在这种情况下 - FILETIME
具有不同的范围。 FILETIME
开始于 在 1/1/1601 并且具有 100 ns 的粒度,它跨越 +/- 30,000 年(或多或少),因为它可以是负数。 DateTime
从 1/1/0001 开始,它有效地使用了 62 位信息(262 刻度),但最大值是 9999 年 12 月 31 日。
另一个问题:从 FILETIME
转换回来时 current implementation 不支持负值,然后有效可用范围在 1601 年 1 月 1 日之间(最小 positive FILETIME
)和 9999 年 12 月 31 日(最大 DateTime
和 DATE
值)。
在处理日期时不要忘记它们(几乎)总是与日历相关联并且某些日历可能有不同的限制:例如台湾日历从 1/1/0001 开始(即 1/1 /1912 公历)和 Um Al Qura 日历 结束 12/29/1450(公历 5/13/2029)。
我正在做一些内存共享,我将在内存共享区域中使用以下结构...
[StructLayout(LayoutKind.Sequential)]
public struct MySharedMemory
{
//Bools
public bool Flag1;
public bool Flag2;
public bool Flag3;
//DateTimes
public DateTime LastWrite;
public DateTime LastRead;
//Longs
public long SrcSize;
//Strings that are a max of 250 characters
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 250)]
public string SrcFile;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 250)]
public string DestFile;
//Ints
public int Count;
//An array of strings that are a max of 100 characters
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100, ArraySubType = UnmanagedType.Struct)]
public FileInfo[] FilesToUpdate;
}
我知道上面的所有定义都是正确的,但 DataTime 除外。我只是添加了那些,但我不确定它们是否是固定大小,或者我需要定义一些特殊的东西,就像我为字符串所做的那样。我的问题是,除了数组和字符串之外,还有没有固定大小的任何类型(特别是我的 DateTime 定义是否正确)?
我会使用 long
,并且只使用 属性 将其公开为 DateTime
:
public struct YourStruct
{
...
private long myTimeAsTicks;
public DateTime MyTime
{
get { return new DateTime(myTimeAsTicks); }
set { myTimeAsTicks = value.Ticks; }
}
...
}
获取结构的实际大小实际上有点棘手,请参阅
不幸的是 DateTime
是一个 weird type 用于封送处理(或者,至少,它有一个非常意外的令人惊讶的行为。)
首先,因为它是一个 Auto
结构(这使得它不可 blittable 并且所有 consequences 大小写)只有一个 long
字段。
你可能会想 wrap 它在一个 blittable 结构中(这里没有什么新鲜事,这是编组非 blittable 类型的 常用方法 ):
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;
}
到目前为止还不错,您可能会想。然而,我们正在转换一个DateTime
(从1/1/0001开始的100 ns滴答数)到一个8字节整数值,在中没有任何等效类型不受管理的 世界。在不受管理的世界中,您可能有:time_t
、FILETIME
、SYSTEMTIME
、DATE
和(许多)其他但none of them exactly matches granularity and range 的 .NET DateTime
。更 annoying 它实际上不是 raw long long
值,因为某些位具有特殊含义,来自源代码:
Bits 63-64: A four-state value that describes the DateTimeKind value of the date time...
你需要一个转换,在这个例子中我选择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);
}
编辑:如何使用?我们定义了两个隐式运算符然后转换 to/from DateTime
是 自动 ,你不需要在托管代码中直接管理 FILETIME
结构(还要注意构造函数是私有的,所有转换都通过定义的运算符进行):
BlittableDateTime time1 = DateTime.UtcNow;
DateTime time2 = time1;
但是我们没有为此类型定义任何比较运算符。如果你不经常这样做,你有两个选择,第一个是铸造:
if ((DateTime)time1 == time2) {
// Do something...
}
或者你可以添加 Value
属性 其中 returns DateTime
(模仿 Nullable<T>
用法):
public DateTime Value
{
get { return (DateTime)this; }
}
这样使用:
if (time1.Value == time2) {
// Do something...
}
关于转换的更多说明。请注意,并非所有转换都是可能的,并且 - 在这种情况下 - FILETIME
具有不同的范围。 FILETIME
开始于 在 1/1/1601 并且具有 100 ns 的粒度,它跨越 +/- 30,000 年(或多或少),因为它可以是负数。 DateTime
从 1/1/0001 开始,它有效地使用了 62 位信息(262 刻度),但最大值是 9999 年 12 月 31 日。
另一个问题:从 FILETIME
转换回来时 current implementation 不支持负值,然后有效可用范围在 1601 年 1 月 1 日之间(最小 positive FILETIME
)和 9999 年 12 月 31 日(最大 DateTime
和 DATE
值)。
在处理日期时不要忘记它们(几乎)总是与日历相关联并且某些日历可能有不同的限制:例如台湾日历从 1/1/0001 开始(即 1/1 /1912 公历)和 Um Al Qura 日历 结束 12/29/1450(公历 5/13/2029)。