Storing System.Type with MongoDb

馋奶兔 提交于 2019-12-22 11:26:21

问题


When I store this class:

class MyClass{
    ...
    public Type SomeType {get;set;} 
    ...
}

SomeType property gets serialized like this:

"SomeType" : {
    "_t" : "RuntimeType"
}

and every subsequent query fails.

I'm using the official C# driver. How do I get it to store the actual Type? Thanks.


回答1:


Here's a sample serializer for System.Type that serializes the name of the Type as a BSON string. This has some limitations in that the Deserialize method fails if the type name is not a system type or in the same assembly, but you could tweak this sample serializer to write the AssemblyQualifiedName instead.

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();
    }
}

The trick is to get it registered properly. You need to register it for both System.Type and System.RuntimeType, but System.RuntimeType is not public so you can't refer to it in your code. But you can get at it using Type.GetType. Here's the code to register the serializer:

var typeSerializer = new TypeSerializer();
BsonSerializer.RegisterSerializer(typeof(Type), typeSerializer);
BsonSerializer.RegisterSerializer(Type.GetType("System.RuntimeType"), typeSerializer);

I used this test loop to verify that it worked:

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);
}

where C is just an empty class:

public static class C
{
}



回答2:


Serializing System.Type is not supported (at least not presently). You will have to store the type name as a string instead.

Alternatively, you could write a serializer for System.Type and register it, but that might be more work than simply storing the type name as a string.



来源:https://stackoverflow.com/questions/8930443/storing-system-type-with-mongodb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!