C# 获取对象结构差异和统计信息的模式,或如何创建差异工具

C# 获取对象结构差异和统计信息的模式,或如何创建差异工具,c#,algorithm,design-patterns,data-structures,comparison,C#,Algorithm,Design Patterns,Data Structures,Comparison,假设我有这样的结构 public class Form { #region Public Properties public List<Field> Fields { get; set; } public string Id { get; set; } public string Name { get; set; } public string Version { get; set; } public int Revision

假设我有这样的结构

public class Form
{
    #region Public Properties

    public List<Field> Fields { get; set; }

    public string Id { get; set; }

    public string Name { get; set; }

    public string Version { get; set; }

    public int Revision { get; set; }

    #endregion
}
public class Field
{
    #region Public Properties

    public string DisplayName { get; set; }

    public List<Field> Fields { get; set; }

    public string Id { get; set; }

    public FieldKind Type { get; set; }

    public FieldType FieldType { get; set; }

    #endregion
}
字段
基本上是复合结构,每个
字段
包含子字段列表。因此,结构是分层的。字段还引用了
字段类型

public class FieldType
{
    #region Public Properties

    public DataType DataType { get; set; }

    public string DisplayName { get; set; }

    public string Id { get; set; }

    #endregion
}
最后我们参考了
数据类型

public class DataType
{
    #region Public Properties

    public string BaseType { get; set; }

    public string Id { get; set; }

    public string Name { get; set; }

    public List<Restriction> Restrictions { get; set; }

    #endregion
}
差异

public struct Difference
{
    public readonly string Property;

    public readonly DifferenceType Type;

    public readonly IExtractionable Expected;

    public readonly IExtractionable Actual;
}
但这可能不是我想要的方式,因为我应该更精确地比较字段,考虑到每个字段都有Id,对于不同的形式,Id也可能不同,我想对比较过程进行更多的控制。对我来说,这听起来更像是一个差异工具


因此,我正在寻找良好的模式和良好的结构,以便将差异发布到客户端代码中,这样可以很容易地将其可视化?

鉴于您的类已经非常有名,我将使用以下内容:

  • 一个IDiffable接口,使类具有DiffWith(T other)类,返回差异枚举。因此,在每个类中实现DiffWith是有意义的,考虑到它们基本上是固定的,这应该很简单

  • 一个单独的ReflectionDiff(可能是静态的)类,它将以使用反射的方式进行比较。这一个可以使用属性来白名单/忽略任何属性/字段。这样,您就可以有一个默认的diff引擎来快速实现差异,并完全使用您正在使用的反射代码。您可以简单地通过以下方式实现diff:

    public override IEnumerable<Difference> DiffWith(Field other)
    {
      return ReflectionDiff.Diff(this, other);
    }
    
    public override IEnumerable DiffWith(字段其他)
    {
    返回ReflectionDiff.Diff(此,其他);
    }
    
您可以得到一个包含所有脏反射代码的类(实际上并不需要),并且可以在每个可扩散类中实现一个简单的DiffWith。

不确定您所追求的解决方案有多优雅,但如果您只是想要一个具有最少编码的快速解决方案,那么可能:

  • 序列化要与文本格式进行比较的实例(例如使用JSON.NET的JSON)
  • 将序列化对象写入文本文件
  • 启动一个diff工具,将这两个文本文件作为参数传递(像ExamDiff这样的工具很容易做到这一点)

  • 正如我所说,这是一个快速的解决方案,但可能足以满足您的需要。另外,还有一些命令行diff工具可供使用,它们将输出一个unix风格的diff文件,然后您可以为该文件编写自己的可视化工具。

    在研究了一点并比较了不同的资源之后,我实现了这种算法

  • 获取对象并构造图形(使用.GetType().GetProperties(),将每个属性添加为根节点的子节点。节点的键将是属性名称
  • 如果遇到任何自定义类型或IEnumerable的属性,请递归执行
  • 创建图形比较器并简单比较两个图形

  • 稍后,我将发布我的代码并更新答案。

    为什么您首先决定使用reflection int?您的类是已知的强类型。您是否也计划在其他类上使用它?也许这个问题与您的相关:尽管给出的答案很有用,但我强烈建议您看看第二个答案swer指出,它有一个“深度对象比较API”,如第8部分所述。嗯,不是真的,现在没有其他类。其想法是创建灵活的解决方案,以后也可以使用它来比较其他类,所以我先尝试反射。
    public override IEnumerable<Difference> DiffWith(Field other)
    {
      return ReflectionDiff.Diff(this, other);
    }