2016-08-18 3 views
3

クラスをBSONドキュメントに変換しようとすると何か問題が発生しました。カスタムBSONキー値シリアライザ

私はCustom1Custom2が少し違うはずです。 KeyValuePairを "展開"して期待される結果を生成するカスタムシリアライザを作成するにはどうすればよいですか(下記参照)?以下のコード例を期待した結果と共に見ることができます。

また、オブジェクトをシリアライズするためにMongo BSONライブラリを使用しています。

public class UserData 
{ 
    public UserData() 
    { 
     Id = 100; 
     Name = "Superuser"; 
     Custom1 = new KeyValuePair<string, double>("HelloWorld1", 1); 
     Custom2 = new KeyValuePair<string, double>("HelloWorld2", 2); 
    } 

    public int Id { get; set; } 
    public string Name { get; set; } 
    public KeyValuePair<string, double> Custom1 { get; set; } 
    public KeyValuePair<string, double> Custom2 { get; set; } 
} 

テストコードを実行します。

var userdata = new UserData(); 
var doc = userdata.ToBsonDocument(); 

現在の結果:

{ 
    "Id": 100, 
    "Name": "Superuser", 
    "Custom1": { 
        "Key": "HelloWorld1", 
        "Value": 1 
       }, 
    "Custom2": { 
        "Key": "HelloWorld2", 
        "Value": 2 
       } 
} 

期待される結果:

{ 
    "Id": 100, 
    "Name": "Superuser", 
    "HelloWorld1": 1, 
    "HelloWorld2": 2 
} 
+0

あなたも得ている結果を親切に投稿してください。 – Newton

+0

@Newton:現在の結果の例が追加されました。 – SOK

答えて

1

このような複雑なシリアライズの場合、クラスにカスタムIBsonSerializerコンバータを実装する必要があります。ここで

は実施例である:

public class UserDataSerializer : SerializerBase<UserData> 
{ 
    public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, UserData value) 
    { 
     context.Writer.WriteStartDocument(); 
     context.Writer.WriteName("Id"); 
     context.Writer.WriteInt32(value.Id); 
     context.Writer.WriteName("Name"); 
     context.Writer.WriteString(value.Name); 

     WriteKeyValue(context.Writer, value.Custom1); 
     WriteKeyValue(context.Writer, value.Custom2); 

     context.Writer.WriteEndDocument(); 
    } 

    private void WriteKeyValue(IBsonWriter writer, KeyValuePair<string, double> kv) 
    { 
     writer.WriteName(kv.Key); 
     writer.WriteDouble(kv.Value); 
    } 

    public override UserData Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) 
    { 
     //TODO: implement data deserialization using context.Reader 
     throw new NotImplementedException(); 
    } 
} 

それはあなたがまた私達のUserDataSerializer何とか登録する必要が動作するように。 IBsonSerializationProviderはそれを達成する最も簡単な方法です。

public class UserDataSerializationProvider : IBsonSerializationProvider 
{ 
    public IBsonSerializer GetSerializer(Type type) 
    { 
     if (type == typeof(UserData)) return new UserDataSerializer(); 
     return null; 
    } 
} 

最後に使用できます。ここで

//register our serialization provider 
BsonSerializer.RegisterSerializationProvider(new UserDataSerializationProvider()); 

var userdata = new UserData(); 
var doc = userdata.ToBsonDocument(); 

が結果です:

{ "Id" : 100, "Name" : "Superuser", "HelloWorld1" : 1.0, "HelloWorld2" : 2.0 } 

また、後方の変換を提供するために、UserDataSerializer.Deserialize()メソッドを実装する必要があります。 context.Readerを使用して同じ方法で実行できます。

カスタムシリアル化プロセスの詳細については、hereを参照してください。

+0

@SOKサンプルを試しましたか?あなたはそれに関する追加の質問がありますか? – kreig

0

あなたがドライバ2.0以降を使用している場合、あなたは可能性をあなたのクラスをダイナミックにしようとするicObjectは、次のように:

var userdata = new UserData(); var doc = ((dynamic) userdata).ToBsonDocument();

および予想されるフォーマットを取得:

public class UserData : DynamicObject 
{ 
public UserData() 
    { 
    Id = 100; 
    Name = "Superuser"; 
    Custom1 = new KeyValuePair<string, double>("HelloWorld1", 1); 
    Custom2 = new KeyValuePair<string, double>("HelloWorld2", 2); 
    } 

public id Id { get; set; } 
public string Name { get; set; } 
public KeyValuePair<string, double> Custom1 { get; set; } 
public KeyValuePair<string, double> Custom2 { get; set; } 

public override bool TryGetMember(
     GetMemberBinder binder, out object result) 
    { 
     string name = binder.Name; 
     result = null; 
     if(name.Equals(Custom1.Key)) 
      result = Custom1.Value; 
     else if(name.Equals(Custom2.Key)) 
      result = Custom2.Value; 
     return result != null; 
    } 

    public override bool TrySetMember(
     SetMemberBinder binder, object value) 
    {   
     string name = binder.Name; 
     if(name.Equals(Custom1.Key)) 
     Custom1.Value = value; 
     else if(name.Equals(Custom2.Key)) 
     Custom2.Value = value; 
     return name.Equals(Custom1.Key) || 
      name.Equals(Custom2.Key); 
    } 
    } 

リリースドキュメントによると、あなたは、これを行うことができるはずです。

+0

TryGetMemberとTrySetMemberは、デフォルトゲッターとセッターをオーバーライドしていますか? – Newton

+0

@ミルトン:あなたの答えをありがとう。私は本当に反射を避けたい。 「カスタム」値の数は実行時に変更されず、 'KeyValuePair'は常に' Key'と 'Value'を持っていますので、' KeyValuePair'を単に "平坦化"するカスタムシリアライザを作ることができます'。 ( '.ToBsonDocument'はリフレクションを使用しますが、マッピングをキャッシュします)。 – SOK

関連する問題