MongoDB自定义序列化器实现

时间:2012-03-20 14:39:57

标签: f# mongodb-.net-driver

我是MongoDB的新手,我正在尝试让C#驱动程序工作序列化F#类。我使用可变F#字段&一个无参数的构造函数,但实际上我需要保持不变性,所以我开始考虑实现一个IBsonSerializer来执行自定义序列化。我还没有找到任何关于编写其中一个的文档,所以我们只是试图从驱动程序源代码中推断出来。

我遇到了一个问题,当在序列化程序上调用Deserialize方法时,CurrentBsonType被设置为EndOfDocument而不是我期待的开始。我在C#中编写了相同的文件只是为了确保它不是一些F#怪异,但问题仍然存在。序列化部分似乎工作正常,可以从shell查询。以下是示例代码:

class Calendar {
    public string Id { get; private set; }
    public DateTime[] Holidays { get; private set; }

    public Calendar(string id, DateTime[] holidays) {
        Id = id;
        Holidays = holidays;
    }
}

class CalendarSerializer : BsonBaseSerializer {
    public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options) {
        var calendar = (Calendar) value;
        bsonWriter.WriteStartDocument();
        bsonWriter.WriteString("_id", calendar.Id);
        bsonWriter.WriteName("holidays");
        var ser = new ArraySerializer<DateTime>();
        ser.Serialize(bsonWriter, typeof(DateTime[]), calendar.Holidays, null);
        bsonWriter.WriteEndDocument();
    }

    public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options) {
        if (nominalType != typeof(Calendar) || actualType != typeof(Calendar))
            throw new BsonSerializationException();

        if (bsonReader.CurrentBsonType != BsonType.Document)
            throw new FileFormatException();

        bsonReader.ReadStartDocument();
        var id = bsonReader.ReadString("_id");
        var ser = new ArraySerializer<DateTime>();
        var holidays = (DateTime[])ser.Deserialize(bsonReader, typeof(DateTime[]), null);
        bsonReader.ReadEndDocument();
        return new Calendar(id, holidays);
    }

    public override bool GetDocumentId(object document, out object id, out Type idNominalType, out IIdGenerator idGenerator) {
        var calendar = (Calendar) document;
        id = calendar.Id;
        idNominalType = typeof (string);
        idGenerator = new StringObjectIdGenerator();
        return true;
    }

    public override void SetDocumentId(object document, object id) {
        throw new NotImplementedException("SetDocumentId is not implemented");
    }
}

当CurrentBsonType不是Document时,在Deserialize中会出现FileFormatException。我使用的是驱动程序源的最新版本1.4。

1 个答案:

答案 0 :(得分:7)

我最终想到了这一点。我应该使用bsonReader.GetCurrentBsonType()而不是bsonReader.CurrentBsonType。这会从缓冲区中读取BsonType,而不是只看那里的最后一件事。我还修复了随后的bug derserializing。更新后的方法如下所示:

public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options) {
    if (nominalType != typeof(Calendar) || actualType != typeof(Calendar))
        throw new BsonSerializationException();

    if (bsonReader.GetCurrentBsonType() != BsonType.Document)
        throw new FileFormatException();

    bsonReader.ReadStartDocument();
    var id = bsonReader.ReadString("_id");
    bsonReader.ReadName();
    var ser = new ArraySerializer<DateTime>();
    var holidays = (DateTime[])ser.Deserialize(bsonReader, typeof(DateTime[]), null);
    bsonReader.ReadEndDocument();
    return new Calendar(id, holidays);
}