Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用JSON.NET自定义引用解析_C#_Json_Json.net - Fatal编程技术网

C# 如何使用JSON.NET自定义引用解析

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

我有以下JSON:

{
           "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;
        }
    }
}