DataContractJsonSerializerはまじめなので、.NETとJSONとの双方向で型が復元されることを前提にしています。そのため、Dictionary<TKey,TValue>を素直にobject表現してくれません。(TKeyがstringに限定され、intなどが復元できないため。TValueの型が不明なため。)
具体的にどうなるかというと
new Dictionary<string,object>{ { "abc", 1 }, { "def", "ghi" } };は
[{"Key":"abc","Value":1},{"Key":"def","Value":"ghi"}]になります。
一般的にJSONを扱う人は
{"abc":1,"def":"ghi"}を期待していることでしょう。
どうにかしたいと思い、必死に対策を考え、遂に実現しました。
class Surrogate: IDataContractSurrogate {
[Serializable]
class JsonDictionary: ISerializable {
Dictionary<string, object> Dictionary { get; set; }
public JsonDictionary( Dictionary<string, object> dictionary ) {
Dictionary = dictionary;
}
public void GetObjectData( SerializationInfo info, StreamingContext context ) {
foreach( var pair in Dictionary )
info.AddValue( pair.Key, pair.Value );
}
}
public Type GetDataContractType( Type type ) {
return type == typeof( Dictionary<string, object> ) ? typeof( JsonDictionary ) : type;
}
public object GetObjectToSerialize( object obj, Type targetType ) {
var dictionary = obj as Dictionary<string, object>;
if( obj == null )
throw new NotImplementedException();
return new JsonDictionary( dictionary );
}
#region NotImplemented
object IDataContractSurrogate.GetCustomDataToExport( Type clrType, Type dataContractType ) {
throw new NotImplementedException();
}
object IDataContractSurrogate.GetCustomDataToExport( MemberInfo memberInfo, Type dataContractType ) {
throw new NotImplementedException();
}
object IDataContractSurrogate.GetDeserializedObject( object obj, Type targetType ) {
throw new NotImplementedException();
}
void IDataContractSurrogate.GetKnownCustomDataTypes( Collection<Type> customDataTypes ) {
throw new NotImplementedException();
}
Type IDataContractSurrogate.GetReferencedTypeOnImport( string typeName, string typeNamespace, object customData ) {
throw new NotImplementedException();
}
CodeTypeDeclaration IDataContractSurrogate.ProcessImportedType( CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit ) {
throw new NotImplementedException();
}
#endregion
}
あとはDataContractJsonSerializerコンストラクタのIDataContractSurrogate引数にSurrogateインスタンスを渡せば、変換してくれます。
もちろん型保証が外れるため、deserializeはできません。