2012-01-19 2 views
1

Когда я храню этот класс:Хранение System.Type с MongoDb

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

SomeType свойство получает сериализован так:

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

и каждый последующий запрос не удается.

Я использую официальный драйвер C#. Как получить его для хранения фактического типа? Спасибо.

ответ

7

Вот пример сериализатора для System.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); 
} 

где С просто пустой класс:

public static class C 
{ 
} 
+0

Отлично, это действительно помогло, спасибо – joe

2

Сериализация System.Type не поддерживается (по крайней мере, не сейчас). Вместо этого вам нужно будет сохранить имя типа в виде строки.

В качестве альтернативы вы можете написать сериализатор для System.Type и зарегистрировать его, но это может быть больше, чем просто сохранение имени типа в виде строки.

+0

Спасибо, Роберт , Я уже сделал это, сохранив имя типа, но я бы предпочел сделать это с помощью пользовательского сериализатора. К сожалению, я не мог найти пример того, как его написать. –

+0

Я попытался написать образец сериализатора для System.Type, но я не думаю, что это возможно. Оказывается, что System.Type является абстрактным базовым классом, но конкретный класс System.RuntimeType, который происходит от него, не является общедоступным. Поскольку наш код не может видеть System.RuntimeType, мы не можем зарегистрировать сериализатор для System.RuntimeType. –

+0

Просто подумал о взломе, чтобы зарегистрировать сериализатор для System.RuntimeType. Я добавляю новый ответ, чтобы описать его. –

Смежные вопросы