一つの可能性は、タイプTTarget
の特定のオブジェクトをシリアル化、custom ContractResolver
を作成することで、指定されたターゲットのために、その対応するDynamicPropertyManager<TTarget>
で指定されたプロパティのIEnumerable<KeyValuePair<Object, Object>>
を返す合成を加算します。
まず、次のように契約リゾルバを定義します。
public class DynamicPropertyContractResolver<TTarget> : DefaultContractResolver
{
readonly DynamicPropertyManager<TTarget> manager;
readonly TTarget target;
public DynamicPropertyContractResolver(DynamicPropertyManager<TTarget> manager, TTarget target)
{
if (manager == null)
throw new ArgumentNullException();
this.manager = manager;
this.target = target;
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
if (objectType == typeof(TTarget))
{
if (contract.ExtensionDataGetter != null || contract.ExtensionDataSetter != null)
throw new JsonSerializationException(string.Format("Type {0} already has extension data.", typeof(TTarget)));
contract.ExtensionDataGetter = (o) =>
{
if (o == (object)target)
{
return manager.Properties.Select(p => new KeyValuePair<object, object>(p.Name, p.GetValue(o)));
}
return null;
};
contract.ExtensionDataSetter = (o, key, value) =>
{
if (o == (object)target)
{
var property = manager.Properties.Where(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase)).SingleOrDefault();
if (property != null)
{
if (value == null || value.GetType() == property.PropertyType)
property.SetValue(o, value);
else
{
var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = this });
property.SetValue(o, JToken.FromObject(value, serializer).ToObject(property.PropertyType, serializer));
}
}
}
};
contract.ExtensionDataValueType = typeof(object);
}
return contract;
}
}
を次に、以下のように、あなたのオブジェクトをシリアル化:必要に応じて出力、
var obj = new object();
//Add prop to instance
int propVal = 0;
var propManager = new DynamicPropertyManager<object>(obj);
propManager.Properties.Add(
DynamicPropertyManager<object>.CreateProperty<object, int>(
"Value", t => propVal, (t, y) => propVal = y, null));
propVal = 3;
var settings = new JsonSerializerSettings
{
ContractResolver = new DynamicPropertyContractResolver<object>(propManager, obj),
};
//Serialize object here
var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
Console.WriteLine(json);
、
{"Value":3}
を明らかにこれは可能性がありコレクションを渡すことによって動的プロパティを持つオブジェクトのグラフを直列化することに拡張することができます動的プロパティマネージャとターゲットのうち、拡張されたものはDynamicPropertyContractResolver<TTarget>
です。コントラクトリゾルバがターゲットから(シリアライズされた)ターゲットからDynamicPropertyManager
にマッピングするためのメカニズムを持っている限り、合成を作成する基本的な考え方は、ExtensionDataGetter
(およびデシリアル化の場合はExtensionDataSetter
)です。
制限:TTarget
タイプのメンバーがすでにextension dataのメンバーである場合、これは機能しません。
出典
2017-10-27 06:51:19
dbc
1)に依存せずに、より一般的なアプローチであるので、私は、これを掲載しています。 ContractResolverできません* - カスタムJson.NETコントラクトリゾルバが動作しなかった理由はわかりません。あなたは間違いなく['CreateProperties()'](https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver_CreateProperties.htm)をオーバーライドし、カスタム合成プロパティを追加することができます。 2)コンソールアプリケーションなどのテスト目的で使用できるカスタムプロパティの最小限の実装を指摘できますか? – dbc
@dbcプロパティは、TypeDescriptorを介してオブジェクト上でしかアクセスできません。タイプからそれらを得ることはできません。後でサンプルの実装を提供します。 CreateProperties(Objectオブジェクト、MemberSerialization memberSerialization)が存在しないことも悪いことです。レゾルバ内のすべてがタイプにリレーされます。 –
@dbcここではDynamicProperties(最小クラス、私はこれをRx Stuffでもっとビルドしました)のGithubリポジトリ(https://github.com/KeilFelix/DynamicProperties)とシリアル化を試してみるConsoleappです –