C# 如何使用JSON.NET自定义引用解析
我有以下JSON:C# 如何使用JSON.NET自定义引用解析,c#,json,json.net,C#,Json,Json.net,我有以下JSON: { "id" : "2" "categoryId" : "35" "type" : "item" "name" : "hamburger" } { "id" : "35" "type" : "category" "name" : "drinks" } 我想把它和这个物体匹配起来: public class Item { [JsonProperty
{
"id" : "2"
"categoryId" : "35"
"type" : "item"
"name" : "hamburger"
}
{
"id" : "35"
"type" : "category"
"name" : "drinks"
}
我想把它和这个物体匹配起来:
public class Item
{
[JsonProperty(PropertyName = "categoryId")]
public Category Category { get; set; }
}
类别
属于实体
类型,该实体具有我可以访问的字符串
Id
属性。我希望JSON反序列化程序创建的“35”对象映射到项中的类别属性
根据,我应该使用IReferenceResolver
。如何实现此接口并将其挂接到JSON.NET框架中?将CustomCreationConverter
用作JsonConverter,并重写Create
和ReadJson
方法
class ItemConverter : CustomCreationConverter<Item> {
public override Item Create(Type objectType)
{
return new Item();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
int categoryId = jObject["categoryId"].ToObject<int>();
Category category = Program.Repository.GetCategoryById(categoryId);
Item result = (Item)base.ReadJson(jObject.CreateReader(), objectType, existingValue, serializer);
result.Category = category;
return result;
}
}
class Item {
[JsonProperty("itemName")]
public string ItemName { get; set; }
public Category Category { get; set; }
// other properties.
}
class Category {
public int CategoryId { get; set; }
public string Name { get; set; }
// other properties.
}
class MockCategoryRepository {
IList<Category> _repository;
public MockCategoryRepository()
{
_repository = new List<Category>();
_repository.Add(new Category() { CategoryId = 1, Name = "Drink" });
_repository.Add(new Category() { CategoryId = 35, Name = "Food" });
_repository.Add(new Category() { CategoryId = 70, Name = "Fruit" });
}
public Category GetCategoryById(int id)
{
return _repository.Where(x => x.CategoryId == id).SingleOrDefault();
}
}
class Program {
public static MockCategoryRepository Repository { get; private set; }
static void Main(string[] args)
{
Repository = new MockCategoryRepository(); // initialize mock repository
// sample : json contains two items in an array.
string jsonString = @"
[
{ ""categoryId"":""35"", ""itemName"":""Item A"" },
{ ""categoryId"":""70"", ""itemName"":""Item B"" },
]";
List<Item> items = JsonConvert.DeserializeObject<List<Item>>(jsonString, new ItemConverter());
}
}
您可以在JsonSerializerSettings中指定自定义IRefinenceResover:
JsonSerializerSettings settings = new JsonSerializerSettings ();
settings.ReferenceResolver = new IDReferenceResolver ();
有一个很好的实现示例,用于具有Guidid属性的对象。引用字符串现在是对象的id,这与您的用例类似,只是您的id属性使用int而不是Guid类型
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class IdReferenceResolver : IReferenceResolver
{
private readonly IDictionary<Guid, PersonReference> _people = new Dictionary<Guid, PersonReference>();
public object ResolveReference(object context, string reference)
{
Guid id = new Guid(reference);
PersonReference p;
_people.TryGetValue(id, out p);
return p;
}
public string GetReference(object context, object value)
{
PersonReference p = (PersonReference)value;
_people[p.Id] = p;
return p.Id.ToString();
}
public bool IsReferenced(object context, object value)
{
PersonReference p = (PersonReference)value;
return _people.ContainsKey(p.Id);
}
public void AddReference(object context, string reference, object value)
{
Guid id = new Guid(reference);
_people[id] = (PersonReference)value;
}
}
}
使用系统;
使用System.Collections.Generic;
使用Newtonsoft.Json.Serialization;
命名空间Newtonsoft.Json.Tests.TestObjects
{
公共类IdReferenceResolver:IReferenceResolver
{
私有只读IDictionary_people=new Dictionary();
公共对象引用(对象上下文、字符串引用)
{
Guid id=新Guid(参考);
个人参考;
_TryGetValue(id,out p);
返回p;
}
公共字符串GetReference(对象上下文、对象值)
{
PersonReference p=(PersonReference)值;
_人[p.Id]=p;
返回p.Id.ToString();
}
公共bool被引用(对象上下文、对象值)
{
PersonReference p=(PersonReference)值;
返回_people.ContainsKey(p.Id);
}
public void AddReference(对象上下文、字符串引用、对象值)
{
Guid id=新Guid(参考);
_人员[id]=(PersonReference)值;
}
}
}
但是如果在主JSON文件的其他地方定义了一个类别,那么不会为相同的类别标识创建重复实例吗?不会,因为在我的示例(内存存储库中),GetCategoryById
只执行搜索,而不创建新的类别
对象。是的,如果您的存储库正在从数据库获取信息(真实案例)。您只需修改ReadJson
方法上的get category算法即可解决问题。如果是这种情况,那么当JSON反序列化程序创建类别时,它必须向存储库注册,或者当它试图创建一个已被引用的类别时,它必须使用现有的类别实例,对的我不知道您的解决方案如何解决这两个问题。您的问题是如何使用Category
属性创建Item
对象,而不是从json字符串创建CategoryId
。您不提供任何有关从何处获得Category
对象的信息。因此,我假设在反序列化包含Item
对象信息的json字符串之前,您已经在代码中获取了category对象列表。如果你认为我对你的问题的理解是错误的,你能更新你的问题以提供更多的细节吗?很抱歉。我会更新这个问题。非常感谢你的帮助。
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class IdReferenceResolver : IReferenceResolver
{
private readonly IDictionary<Guid, PersonReference> _people = new Dictionary<Guid, PersonReference>();
public object ResolveReference(object context, string reference)
{
Guid id = new Guid(reference);
PersonReference p;
_people.TryGetValue(id, out p);
return p;
}
public string GetReference(object context, object value)
{
PersonReference p = (PersonReference)value;
_people[p.Id] = p;
return p.Id.ToString();
}
public bool IsReferenced(object context, object value)
{
PersonReference p = (PersonReference)value;
return _people.ContainsKey(p.Id);
}
public void AddReference(object context, string reference, object value)
{
Guid id = new Guid(reference);
_people[id] = (PersonReference)value;
}
}
}