如何通过比较两个c#对象来创建JsonPatchDocument?

如何通过比较两个c#对象来创建JsonPatchDocument?,c#,json-patch,C#,Json Patch,考虑到我有两个相同类型的c#对象,我想比较它们来创建一个JsonPatchDocument 我有一个定义如下的StyleDetail类: public class StyleDetail { public string Id { get; set; } public string Code { get; set; } public string Name { get; set; } public decimal Origin

考虑到我有两个相同类型的c#对象,我想比较它们来创建一个JsonPatchDocument

我有一个定义如下的StyleDetail类:

public class StyleDetail
    {
        public string Id { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
        public decimal OriginalPrice { get; set; }
        public decimal Price { get; set; }
        public string Notes { get; set; }
        public string ImageUrl { get; set; }
        public bool Wishlist { get; set; }
        public List<string> Attributes { get; set; }
        public ColourList Colours { get; set; }
        public SizeList Sizes { get; set; }
        public ResultPage<Style> Related { get; set; }
        public ResultPage<Style> Similar { get; set; }
        public List<Promotion> Promotions { get; set; }
        public int StoreStock { get; set; }
        public StyleDetail()
        {
            Attributes = new List<string>();
            Colours = new ColourList();
            Sizes = new SizeList();
            Promotions = new List<Promotion>();
        }
    }
现在我想创建一个JSONPATCH文档,这样我就可以将差异发送到我的RESTAPI。。。怎么做

JsonPatchDocument patch = new JsonPatchDocument();
// Now I want to populate patch with the differences between styleNew and styleOld - how?
在javascript中,有一个库来实现这一点

计算两个对象之间的差异:

rfc6902.createPatch({first:'Chris'},{first:'Chris',last: “棕色”})


但是我正在寻找一个c#实现

让我们滥用这样一个事实:您的类可以序列化为JSON! 这是补丁创建者的第一次尝试,它不关心您的实际对象,只关心该对象的JSON表示

public static JsonPatchDocument CreatePatch(object originalObject, object modifiedObject)
{
    var original = JObject.FromObject(originalObject);
    var modified = JObject.FromObject(modifiedObject);

    var patch = new JsonPatchDocument();
    FillPatchForObject(original, modified, patch, "/");

    return patch;
}

static void FillPatchForObject(JObject orig, JObject mod, JsonPatchDocument patch, string path)
{
    var origNames = orig.Properties().Select(x => x.Name).ToArray();
    var modNames = mod.Properties().Select(x => x.Name).ToArray();

    // Names removed in modified
    foreach (var k in origNames.Except(modNames))
    {
        var prop = orig.Property(k);
        patch.Remove(path + prop.Name);
    }

    // Names added in modified
    foreach (var k in modNames.Except(origNames))
    {
        var prop = mod.Property(k);
        patch.Add(path + prop.Name, prop.Value);
    }

    // Present in both
    foreach (var k in origNames.Intersect(modNames))
    {
        var origProp = orig.Property(k);
        var modProp = mod.Property(k);

        if (origProp.Value.Type != modProp.Value.Type)
        {
            patch.Replace(path + modProp.Name, modProp.Value);
        }
        else if (!string.Equals(
                        origProp.Value.ToString(Newtonsoft.Json.Formatting.None),
                        modProp.Value.ToString(Newtonsoft.Json.Formatting.None)))
        {
            if (origProp.Value.Type == JTokenType.Object)
            {
                // Recurse into objects
                FillPatchForObject(origProp.Value as JObject, modProp.Value as JObject, patch, path + modProp.Name +"/");
            }
            else
            {
                // Replace values directly
                patch.Replace(path + modProp.Name, modProp.Value);
            }
        }       
    }
}
用法:

var patch = CreatePatch(
    new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "1", Removed = "1" },
    new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "2", Added = new { x = "1" } });

// Result of JsonConvert.SerializeObject(patch)
[
  {
    "path": "/Removed",
    "op": "remove"
  },
  {
    "value": {
      "x": "1"
    },
    "path": "/Added",
    "op": "add"
  },
  {
    "value": "2",
    "path": "/Changed",
    "op": "replace"
  }
]
你可以用

您可以使用NuGet进行安装,请参阅NuGet.org上的SimpleHelpers.ObjectDiffPatch

PM> Install-Package SimpleHelpers.ObjectDiffPatch
使用:


你可以用我的分析仪。它基于反射,您可以配置要分析的深度


我知道这已经有点过时了。。。但是你知道怎么做吗?我在找完全一样的东西!您可以使用反射来迭代属性并比较它们。关于迭代属性的示例,请参见此问题:顺便说一句,您也可以使用完全相同的代码来区分JSON字符串,只需从字符串创建作业对象,然后调用
FillPatchForObject
谢谢!帮了大忙。但是如果我们改变“颜色”,例如在“StyleDetail”类中,它就不能正常工作。如果直接序列化,“StyleDetail”是否正确地序列化为JSON?否则,我的方法就行不通了。你能给出StyleDetail的定义,以及两个给出错误的示例对象吗?这里的区别是数组。我并没有试图以一种好的方式处理数组,我只是在有差异的情况下替换整个数组。一个元素一个元素地比较并不困难,但是想象一下,如果您有一个包含700个元素的数组,并且删除了元素0。检测这些变化是复杂的。比较数组的简单方法是“替换”元素0-698,然后删除元素699。这里有一个更新版本,支持替换数组元素而不是整个数组。这并不能回答问题。您正在代码中手动添加要替换的项,而不是通过比较两个ObjectsOry来生成修补程序文档。我修复了它。此项目进行了区分,但没有生成JSONPatchDocument。这是否返回json修补程序?不,您仍然需要将结果转换为JsonPatch。你会有所有的不同。
var patch = CreatePatch(
    new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "1", Removed = "1" },
    new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "2", Added = new { x = "1" } });

// Result of JsonConvert.SerializeObject(patch)
[
  {
    "path": "/Removed",
    "op": "remove"
  },
  {
    "value": {
      "x": "1"
    },
    "path": "/Added",
    "op": "add"
  },
  {
    "value": "2",
    "path": "/Changed",
    "op": "replace"
  }
]
PM> Install-Package SimpleHelpers.ObjectDiffPatch
StyleDetail styleNew = new StyleDetail() { Id = "12", Code = "first" };
StyleDetail styleOld = new StyleDetail() { Id = "23", Code = "second" };
var diff = ObjectDiffPatch.GenerateDiff (styleOld , styleNew );

// original properties values
Console.WriteLine (diff.OldValues.ToString());

// updated properties values
Console.WriteLine (diff.NewValues.ToString());
var before = new User { Id = 1, Name="foo"};
var after= new User  { Id = 2, Name="bar"};
var analyzer = new DiffAnalyzer();
var results = analyzer.Compare(before, after);