You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Microsoft PersistentDictionary创建自定义结构体类型实例失败的问题咨询

解决PersistentDictionary自定义结构体的异常与编译错误问题

我帮你梳理下问题的根源和解决办法:

首先解决编译错误:Serializable属性的误用

你提到添加[Serializable]时出现CS8124和IDE1007错误,这是因为你可能不小心写错了属性语法——正确的[Serializable]属性不需要额外的括号和内容(比如错误的[Serializable](Serializable)写法)。你的代码里已经引用了System命名空间(using System;),所以修正结构体定义即可:

[Serializable]
public struct MyStruct
{
    public bool ABoolean;
    public long ALong;
}

这个语法错误修复后,编译问题就会消失,但还需要解决核心的运行时异常。

核心问题:自定义结构体不被Esent引擎支持

PersistentDictionary基于Esent数据库,它对值类型的支持有严格限制:

  • 仅支持Esent原生兼容的值类型(比如int、DateTime、bool、byte[]等)
  • 自定义类型要作为字典值,要么是标记了[Serializable]的类(引用类型),要么是实现IEsentSerializable接口来自定义序列化逻辑

你的MyStruct是值类型(结构体),即便标记了[Serializable],Esent也无法将它映射到数据库列,因此抛出ArgumentOutOfRangeException。

可行的解决方案

方案1:把结构体改成类(最简单)

将MyStruct改为引用类型(类),保留[Serializable]属性,PersistentDictionary会自动处理序列化:

[Serializable]
public class MyClass
{
    public bool ABoolean;
    public long ALong;
}

// 实例化字典
PersistentDictionary<int, MyClass> pd2 = new PersistentDictionary<int, MyClass>("PersistentDict");

这样修改后,代码就能像DateTime版本一样正常运行。

方案2:手动序列化结构体为byte[]存储(保留结构体)

如果必须使用结构体,可以把它序列化为byte[],将字典类型定义为PersistentDictionary<int, byte[]>,读写时手动处理序列化:

// 序列化方法
private static byte[] SerializeMyStruct(MyStruct data)
{
    using var ms = new MemoryStream();
    var formatter = new BinaryFormatter();
    formatter.Serialize(ms, data);
    return ms.ToArray();
}

// 反序列化方法
private static MyStruct DeserializeMyStruct(byte[] data)
{
    using var ms = new MemoryStream(data);
    var formatter = new BinaryFormatter();
    return (MyStruct)formatter.Deserialize(ms);
}

// 使用示例
var pd2 = new PersistentDictionary<int, byte[]>("PersistentDict");
var myData = new MyStruct { ABoolean = true, ALong = 12345 };
pd2[1] = SerializeMyStruct(myData);

// 读取数据
var storedData = DeserializeMyStruct(pd2[1]);

pd2.Flush();
pd2.Dispose();

注意:在.NET Core/.NET 5+中使用BinaryFormatter需要安装System.Runtime.Serialization.Formatters.Binary NuGet包。

方案3:实现IEsentSerializable接口(高性能)

如果追求更好的性能,可以让结构体实现IEsentSerializable接口,自定义与Esent列的交互逻辑:

using Microsoft.Isam.Esent.Interop;

public struct MyStruct : IEsentSerializable
{
    public bool ABoolean;
    public long ALong;

    public void Serialize(JET_COLUMNID columnid, JET_SESID sesid, JET_TABLEID tableid)
    {
        // 将结构体字段序列化为字节流写入Esent列
        using var ms = new MemoryStream();
        using var writer = new BinaryWriter(ms);
        writer.Write(ABoolean);
        writer.Write(ALong);
        Api.SetColumn(sesid, tableid, columnid, ms.ToArray());
    }

    public void Deserialize(JET_COLUMNID columnid, JET_SESID sesid, JET_TABLEID tableid)
    {
        // 从Esent列读取字节流并反序列化为结构体
        var data = Api.RetrieveColumn(sesid, tableid, columnid);
        using var ms = new MemoryStream(data);
        using var reader = new BinaryReader(ms);
        ABoolean = reader.ReadBoolean();
        ALong = reader.ReadInt64();
    }
}

这种方式需要熟悉Esent的API,但能避免通用序列化的开销,适合性能敏感的场景。

验证

选择任意一种方案修改后,你可以重复之前的测试流程,自定义类型的字典应该能正常创建、写入和释放资源了。

内容的提问来源于stack exchange,提问作者Rowan Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 12:52:35