使用MongoDb存储System.Type

Vie*_*orm 1 mongodb mongodb-.net-driver

当我存储这个类时:

class MyClass{
    ...
    public Type SomeType {get;set;} 
    ...
}
Run Code Online (Sandbox Code Playgroud)

SomeType属性像这样序列化:

"SomeType" : {
    "_t" : "RuntimeType"
}
Run Code Online (Sandbox Code Playgroud)

并且每个后续查询都失败.

我正在使用官方的C#驱动程序.如何让它存储实际类型?谢谢.

Rob*_*tam 7

这是System.Type的示例序列化程序,它将Type的名称序列化为BSON字符串.这有一些局限性,如果类型名称不是系统类型或在同一程序集中,则Deserialize方法会失败,但您可以调整此示例序列化程序以编写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();
    }
}
Run Code Online (Sandbox Code Playgroud)

诀窍是让它正确注册.您需要为System.Type和System.RuntimeType注册它,但System.RuntimeType不是公共的,因此您不能在代码中引用它.但是你可以使用Type.GetType来实现它.这是注册序列化器的代码:

var typeSerializer = new TypeSerializer();
BsonSerializer.RegisterSerializer(typeof(Type), typeSerializer);
BsonSerializer.RegisterSerializer(Type.GetType("System.RuntimeType"), typeSerializer);
Run Code Online (Sandbox Code Playgroud)

我用这个测试循环验证它是否有效:

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);
}
Run Code Online (Sandbox Code Playgroud)

其中C只是一个空类:

public static class C
{
}
Run Code Online (Sandbox Code Playgroud)