2017-08-17 43 views
1

手元にあるプロジェクトでは、シリアル化にDataContractJsonSerializerを使用し、メンバーの値に基づいて特定の出力を生成する必要があります。DataContractJsonSerializerの出力形式を指定しますか?

私のクラスは次のようになります。

public class MyClass 
{ 
    public string foo; 
    public string bar; 

    public MyClass(string f, string b = "") 
    { 
    this.foo = f; 
    this.bar = b; 
    } 
} 

var list = new List<MyClass> 
{ 
    new MyClass("foo", "bar"), 
    new MyClass("foo1"), 
    new MyClass("foo2", "bar2") 
}; 

ようなリストのシリアライズはこの

[{"foo": "bar"}, "foo1", {"foo2": "bar2"}] 

かのようになります - いっそ - 脱出してa:

"[{\"foo\": \"bar\"}, \"foo1\", {\"foo2\": \"bar2\"}]" 
  • 文字列とオブジェクトが混在しています。どうすればこれを達成できますか?

IはToString()メソッドをオーバーライドして、不必要にエスケープ記号、例えば、その結果、対応する文字列を直列化しようとしましたbar2m/sで、m\\/sとしてエスケープされましたが、これはWebサーバー上で正しくデシリアライズできませんでした。

最後に、この形式にシリアル化するだけで済みます。 DataContractJsonSerializerでこの形式を逆シリアル化する必要はありません。

+0

その結果[データコントラクトタイプ](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/types-supported-by-the-data-contract-serializer)をializingします。基になるシリアライズされたフォーマット(JSONまたはXML)へのアクセスを提供します。 – dbc

+0

[tag:json.net]に切り替えた場合、これは簡単に実行できます。あるいは、['JsonReaderWriterFactory.CreateJsonWriter()'](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/types-supported-by-the-data-contract)を呼び出すこともできます。 JSONとXML間のマッピング](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/mapping-between)に記載されている規則に従って、独自のJSON出力を手動でシリアル化します。 -json-and-xml)。 – dbc

+0

私はこの形式にシリアル化する必要があります。 – vonludi

答えて

1

あなたがやりたい何が条件付きしかし、プリミティブを使用して、stringまたは辞書ですserialization surrogateMyClassのインスタンスを置き換えることですMicrosoftがhereで説明したように、代理人がデータコントラクトのシリアル化によってサポートされていないためです。あなたが唯一のシリアライズとデシリアライズないようにする必要がありますので、

しかし、あなたは手動でMyClassのインスタンスはbarが空の文字列に置き換えた代理List<object>であなたList<MyClass>を置き換えることにより、必要な出力を取得し、Dictionary<string, string>することができますさもないと。手動constructDataContractJsonSerializerSettingsで次の値でDataContractJsonSerializer

DataContractJsonSerializerSettingsEmitTypeInformationUseSimpleDictionaryFormatは、.NET 4.5に、すべての新しいをしていることに注意してください。)このように

あなたが定義することができ、あなたのMyTypeを次のように:

public static partial class DataContractJsonSerializerHelper 
{ 
    public static string SerializeJsonSurrogateCollection<T>(this IEnumerable<T> collection) where T : IHasSerializationSurrogate 
    { 
     if (collection == null) 
      throw new ArgumentNullException(); 
     var surrogate = collection.Select(i => i == null ? null : i.ToSerializationSurrogate()).ToList(); 
     var settings = new DataContractJsonSerializerSettings 
     { 
      EmitTypeInformation = EmitTypeInformation.Never, 
      KnownTypes = surrogate.Where(s => s != null).Select(s => s.GetType()).Distinct().ToList(), 
      UseSimpleDictionaryFormat = true, 
     }; 
     return DataContractJsonSerializerHelper.SerializeJson(surrogate, settings); 
    } 

    public static string SerializeJson<T>(this T obj, DataContractJsonSerializerSettings settings) 
    { 
     var type = obj == null ? typeof(T) : obj.GetType(); 
     var serializer = new DataContractJsonSerializer(type, settings); 
     return SerializeJson<T>(obj, serializer); 
    } 

    public static string SerializeJson<T>(this T obj, DataContractJsonSerializer serializer = null) 
    { 
     serializer = serializer ?? new DataContractJsonSerializer(obj == null ? typeof(T) : obj.GetType()); 
     using (var memory = new MemoryStream()) 
     { 
      serializer.WriteObject(memory, obj); 
      memory.Seek(0, SeekOrigin.Begin); 
      using (var reader = new StreamReader(memory)) 
      { 
       return reader.ReadToEnd(); 
      } 
     } 
    } 
} 

をし、次のように手動でJSONへのあなたのリストをシリアライズ:

public interface IHasSerializationSurrogate 
{ 
    object ToSerializationSurrogate(); 
} 

public class MyClass : IHasSerializationSurrogate 
{ 
    public string foo; 
    public string bar; 

    // If you're not going to mark MyClass with data contract attributes, DataContractJsonSerializer 
    // requires a default constructor. It can be private. 
    MyClass() : this("", "") { } 

    public MyClass(string f, string b = "") 
    { 
     this.foo = f; 
     this.bar = b; 
    } 

    public object ToSerializationSurrogate() 
    { 
     if (string.IsNullOrEmpty(bar)) 
      return foo; 
     return new Dictionary<string, string> { { foo, bar } }; 
    } 
} 

は、その後、次の拡張メソッドを紹介

var json = list.SerializeJsonSurrogateCollection(); 

次の結果を得ました:

[{"foo":"bar"},"foo1",null,{"foo2":"bar2"}] 

あなたは本当にあなたが常に二重シリアル化された結果生じるDataContractJsonSerializerとJSON 二度目に結果の文字列をシリアル化することができます(なぜ?)エスケープする文字列が必要な場合:

var jsonOfJson = json.SerializeJson(); 

を私はそれがSerためDataContractSerializer` `とコードベースを共有しているため、純粋にDataContractJsonSerializer``でこれを行う方法はありません信じて

"[{\"foo\":\"bar\"},\"foo1\",{\"foo2\":\"bar2\"}]" 
+0

これは正しい方向だと思います。それでも、私が必要とする出力は、barが空で、 '{" [foo value] ":" [bar value] "}'でなければ '' [foo value] ''として与えられます。 – vonludi

+0

@vonludi - 私はそれを逃したと信じられない。回答が更新されました。 – dbc

+0

ありがとうございます。 「なぜ脱出するのか」質問:私はこの答えに従ってhttpwebrequestで文字列を使用する際に文字列をエスケープする必要があると思います。https://stackoverflow.com/questions/20510437/use-c-sharp-httpwebrequest-to-send-json-to-web- service/20511017#20511017 – vonludi

0

デシリアライズは名前と値の組み合わせに基づいて行われるため、テキストは次のようになります [{"" foo "、" bar ":" bar "}、{" foo ":" foo1 "}、 {「foo」という:「foo2は」、「バー」:「BAR2」}]

+0

それで、必要な出力を得るためにオーバーライドまたは実装することは決してできないと言っていますか?そうでない場合は、{[foo]の値:[value of bar]}であり、そうでなければ[value of foo]です。 – vonludi