存储系统。使用MongoDb键入

存储系统。使用MongoDb键入,mongodb,mongodb-.net-driver,Mongodb,Mongodb .net Driver,当我存储此类时: class MyClass{ ... public Type SomeType {get;set;} ... } SomeType属性的序列化方式如下: "SomeType" : { "_t" : "RuntimeType" } 随后的每个查询都会失败 我用的是官方的C#driver。如何让它存储实际类型? 谢谢。序列化系统。不支持类型(至少目前不支持)。您必须将类型名称存储为字符串 或者,您可以为System.Type编写序列化程序并注册

当我存储此类时:

class MyClass{
    ...
    public Type SomeType {get;set;} 
    ...
}
SomeType属性的序列化方式如下:

"SomeType" : {
    "_t" : "RuntimeType"
}
随后的每个查询都会失败

我用的是官方的C#driver。如何让它存储实际类型?
谢谢。

序列化系统。不支持类型(至少目前不支持)。您必须将类型名称存储为字符串


或者,您可以为System.Type编写序列化程序并注册它,但这可能比简单地将类型名称存储为字符串要复杂。

下面是System.Type的序列化程序示例,它将类型名称序列化为BSON字符串。这有一些限制,因为如果类型名称不是系统类型或不在同一程序集中,反序列化方法将失败,但您可以调整此示例序列化程序,改为编写AssemblyQualifiedName

public class TypeSerializer : IBsonSerializer
{
    public object Deserialize(BsonReader reader, Type nominalType, IBsonSerializationOptions options)
    {
        var actualType = nominalType;
        return Deserialize(reader, nominalType, actualType, options);
    }

    public object Deserialize(BsonReader reader, Type nominalType, Type actualType, IBsonSerializationOptions options)
    {
        if (reader.CurrentBsonType == BsonType.Null)
        {
            return null;
        }
        else
        {
            var fullName = reader.ReadString();
            return Type.GetType(fullName);
        }
    }

    public bool GetDocumentId(object document, out object id, out Type idNominalType, out IIdGenerator idGenerator)
    {
        throw new InvalidOperationException();
    }

    public void Serialize(BsonWriter writer, Type nominalType, object value, IBsonSerializationOptions options)
    {
        if (value == null)
        {
            writer.WriteNull();
        }
        else
        {
            writer.WriteString(((Type)value).FullName);
        }
    }

    public void SetDocumentId(object document, object id)
    {
        throw new InvalidOperationException();
    }
}
诀窍是让它正确注册。您需要为System.Type和System.RuntimeType注册它,但System.RuntimeType不是公共的,因此您不能在代码中引用它。但是您可以使用Type.GetType来获得它。以下是注册序列化程序的代码:

var typeSerializer = new TypeSerializer();
BsonSerializer.RegisterSerializer(typeof(Type), typeSerializer);
BsonSerializer.RegisterSerializer(Type.GetType("System.RuntimeType"), typeSerializer);
我使用这个测试循环来验证它是否有效:

var types = new Type[] { typeof(int), typeof(string), typeof(Guid), typeof(C) };
foreach (var type in types)
{
    var json = type.ToJson();
    Console.WriteLine(json);
    var rehydratedType = BsonSerializer.Deserialize<Type>(json);
    Console.WriteLine("{0} -> {1}", type.FullName, rehydratedType.FullName);
}

谢谢,罗伯特。我已经通过存储类型名实现了这一点,但我更愿意使用自定义序列化程序。不幸的是,我找不到如何编写的示例。我试图为System.Type编写一个示例序列化程序,但我认为这是不可能的。结果表明System.Type是一个抽象基类,但从它派生的具体类System.RuntimeType不公开可见。因为我们的代码看不到System.RuntimeType,所以我们无法为System.RuntimeType注册序列化程序。只是想到了一个为System.RuntimeType注册序列化程序的方法。我正在添加一个新的答案来描述它。
public static class C
{
}