tri*_*dev 5 .net c# serialization json.net
我需要为我使用Json.Net序列化的每个对象添加一个'type'属性.我知道Json.Net已经支持这个开箱即用,但在我的情况下,类型名称需要排除程序集,并且属性的名称必须是可配置的(两者都不受支持).
我目前有这个:
public class TypeConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serialiser)
{
JObject jObject = JObject.FromObject(value, serializer);
jObject.AddFirst(new JProperty("myCustomTypePropertyName"), value.GetType().Name);
jObject.WriteTo(writer);
}
public override void ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serialiser)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return objectType.IsClass;
}
}
Run Code Online (Sandbox Code Playgroud)
这适用于正在序列化的外部类型,但遗憾的是没有为嵌套对象调用转换器.如果我将序列化器添加到JObject.FromObject调用中,那么我会尝试重新进入外部类型的转换器时出现自引用循环异常.
我可以解决这个问题的唯一方法是手动反映和迭代每个级别的属性,并使用serializer参数对它们进行序列化,但即使在考虑性能之前,它也非常难看.
我很感激对此的一些帮助; 我希望我遗漏了一些明显的东西.
(注意:我正在运行.NET 3.5,因此SerializationBinder是不可能的.)
不,你不会错过任何明显的东西.尝试用JsonConverter处理各种类的方法来做这件事会因为你已经看到的原因而成问题.JsonConverters最适合处理特定类型; 他们不善于概括.幸运的是,有一种方法可以使用自定义来执行您想要的操作IContractResolver.
合同解析器允许我们在属性级别上对各种类应用某些序列化行为.这个想法是让解析器在每个类上伪造一个额外的"类型名称"属性(或者你想要它被调用的任何属性)并安装一个对应的IValueProvider,以便在序列化每个对象时提供该属性的值.(这样,序列化器永远不会知道该属性确实不存在.)
创建解析器的最简单方法是从DefaultContractResolverJson.Net附带的方法中获取它.从那里我们只需要覆盖该CreateProperties()方法并将我们的假属性注入从基类返回的列表中.
以下是解析程序和值提供程序的代码:
class CustomResolver : DefaultContractResolver
{
private string customTypePropertyName;
private IValueProvider valueProvider = new SimpleTypeNameProvider();
public CustomResolver(string customTypePropertyName)
{
this.customTypePropertyName = customTypePropertyName;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
if (type.IsClass && type != typeof(string))
{
// Add a phantom string property to every class which will resolve
// to the simple type name of the class (via the value provider)
// during serialization.
props.Insert(0, new JsonProperty
{
DeclaringType = type,
PropertyType = typeof(string),
PropertyName = customTypePropertyName,
ValueProvider = valueProvider,
Readable = true,
Writable = false
});
}
return props;
}
class SimpleTypeNameProvider : IValueProvider
{
public object GetValue(object target)
{
return target.GetType().Name;
}
public void SetValue(object target, object value)
{
return;
}
}
}
Run Code Online (Sandbox Code Playgroud)
要使用解析器,请创建一个实例并通过JsonSerializerSettings对象将其传递给序列化程序.这是一个简短的演示:
class Program
{
static void Main(string[] args)
{
Person p = new Person
{
Id = 2,
Name = "Peter",
Employer = new Company
{
Id = 5,
Name = "Initech"
}
};
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver("MyTypeName"),
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(p, settings);
Console.WriteLine(json);
}
}
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Company Employer { get; set; }
}
class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
输出:
{
"MyTypeName": "Person",
"Id": 2,
"Name": "Peter",
"Employer": {
"MyTypeName": "Company",
"Id": 5,
"Name": "Initech"
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1486 次 |
| 最近记录: |