【问题标题】:Fixed-length string as value type for use in MemoryMappedViewAccessor固定长度字符串作为值类型用于 MemoryMappedViewAccessor
【发布时间】:2011-11-17 23:03:35
【问题描述】:

我想将一个结构存储到 MemoryMappedFile 中,但该结构包含引用类型的字符串(具有我知道的最大大小),因此被 MemoryMappedViewAccessor 拒绝。

你知道一个好的定长字符串结构(值类型)实现吗?如果有必要,我可以硬编码长度(因为数组是引用类型)。

例如,我可以将其实例化为:

TenCharsString myString = new TenCharsString("1234567890");

使用 MarshalAs 属性进行装饰

<MarshalAs (UnmanagedType.ByValTStr, SizeConst:=128)> 

应该可以,但是不行。

【问题讨论】:

  • MemoryMappedFiles 不使用像 P/Invoke 这样的编组。它们直接在托管内存和文件之间复制字节。
  • 抛出的异常是什么?结构是什么样的?
  • MemoryMappedViewAccessor 只接受值类型,包括结构体,只要它们只包含值类型(没有引用类型,如字符串)。我的结构包含 datetimeoffset?、decimal?、long? 和两个导致问题的字符串字段(尽管它们的长度在数据库中是固定的)。

标签: c# .net string types


【解决方案1】:

这是一个简单的 10 字符值类型:

struct TenChars
{
    public char A;
    public char B;
    public char C;
    public char D;
    public char E;
    public char F;
    public char G;
    public char H;
    public char I;
    public char J;
}

如果不安全的代码是一个选项,这也可以:

unsafe struct TenChars
{
    public fixed char Chars[10];
}

完整代码:

struct TenChars1
{
    public const int Capacity = 10;

    private char A;
    private char B;
    private char C;
    private char D;
    private char E;
    private char F;
    private char G;
    private char H;
    private char I;
    private char J;

    public TenChars1(string value)
    {
        if (value == null) throw new ArgumentNullException("value");
        if (value.Length > Capacity) throw new ArgumentException();

        A = (value.Length > 0) ? value[0] : '\0';
        B = (value.Length > 1) ? value[1] : '\0';
        C = (value.Length > 2) ? value[2] : '\0';
        D = (value.Length > 3) ? value[3] : '\0';
        E = (value.Length > 4) ? value[4] : '\0';
        F = (value.Length > 5) ? value[5] : '\0';
        G = (value.Length > 6) ? value[6] : '\0';
        H = (value.Length > 7) ? value[7] : '\0';
        I = (value.Length > 8) ? value[8] : '\0';
        J = (value.Length > 9) ? value[9] : '\0';
    }

    public override string ToString()
    {
        return new string(new char[] { A, B, C, D, E, F, G, H, I, J });
    }
}

unsafe struct TenChars2
{
    public const int Capacity = 10;

    private fixed char buffer[Capacity];

    public TenChars2(string value)
    {
        if (value == null) throw new ArgumentNullException("value");
        if (value.Length > Capacity) throw new ArgumentException();

        fixed (char* ptr = this.buffer)
        fixed (char* chars = value)
        {
            for (int i = 0; i < value.Length; i++)
            {
                *(ptr + i) = *(chars + i);
            }
        }
    }

    public override string ToString()
    {
        fixed (char* ptr = this.buffer)
        {
            return new string(ptr);
        }
    }
}

【讨论】:

  • 谢谢!您认为哪种实现会更快?以及使用不安全的版本会有什么样的风险(糟糕的内存管理?)?
  • 对于这么少的字符,速度应该不会有太大差异。如果速度很关键,请使用分析器。不安全代码越过了托管代码的安全边界,可能很危险。如果您不习惯处理不安全的代码,我建议您使用安全的实现。
【解决方案2】:

您可以单独存储结构内部。您可以使用WriteArrayReadArray 将字符串存储为字符数组。其他人可以使用各种Write methods

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多