使用 MongoDb 存储 System.Type

发布于 2024-12-27 19:16:01 字数 270 浏览 0 评论 0原文

当我存储此类时:

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

SomeType 属性会像这样序列化:

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

并且每个后续查询都会失败。

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

花开柳相依 2025-01-03 19:16:01

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

诀窍是正确注册它。您需要为 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);
}

其中 C 只是一个空类:

public static class C
{
}

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
{
}
守护在此方 2025-01-03 19:16:01

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文