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

Jev*_*sov 8 c# algorithm comparison design-patterns data-structures

假设我有这样的结构

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
}
Run Code Online (Sandbox Code Playgroud)

所以Form该类包含字段列表,假设字段本身用这种结构表示

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
}
Run Code Online (Sandbox Code Playgroud)

Field基本上是复合结构,每个Field包含子字段列表.所以结构是分层的.Field也参考了这门FieldType课程.

public class FieldType
{
    #region Public Properties

    public DataType DataType { get; set; }

    public string DisplayName { get; set; }

    public string Id { get; set; }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

最后我们参考了 DataType

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
}
Run Code Online (Sandbox Code Playgroud)

我想要实现的是获得这种复杂结构的差异,让我们说如果我有某种Comparer,它会给我整个表单作为一个类的结构化差异,让我们说差异结果.当我说结构化差异时,我的意思是它应该是那样的.

  1. Form字段的差异(输出Form在版本字段中有差异(不同的颜色)
  2. Fields集合的差异,包括已编辑字段的字段层次结构
  3. 对于同样的行为FieldTypeDataType
  4. 检测删除并添加FieldForm(因此可能每个差异都有一个类型)

我现在有什么 我开始使用泛型方法并尝试使用ReflectionComparer实现IEqualityComparer接口

public bool Equals(T x, T y)
{
    var type = typeof(T);

    if (typeof(IEquatable<T>).IsAssignableFrom(type))
    {
        return EqualityComparer<T>.Default.Equals(x, y);
    }

    var enumerableType = type.GetInterface(typeof(IEnumerable<>).FullName);

    if (enumerableType != null)
    {
        var elementType = enumerableType.GetGenericArguments()[0];
        var elementComparerType = typeof(DifferenceComparer<>).MakeGenericType(elementType);

        var elementComparer = Activator.CreateInstance(elementComparerType, new object[] { _foundDifferenceCallback, _existedDifference });

        return (bool)typeof(Enumerable).GetGenericMethod("SequenceEqual", new[] { typeof(IEnumerable<>), typeof(IEnumerable<>), typeof(IEqualityComparer<>) }).MakeGenericMethod(elementType).Invoke(null, new[] { x, y, elementComparer });
    }

    foreach (var propertyInfo in type.GetProperties())
    {
        var leftValue = propertyInfo.GetValue(x);
        var rightValue = propertyInfo.GetValue(y);

        if (leftValue != null)
        {
            var propertyComparerType = typeof(DifferenceComparer<>).MakeGenericType(propertyInfo.PropertyType);

            var propertyComparer = Activator.CreateInstance(propertyComparerType, new object[] {_foundDifferenceCallback, _existedDifference});

            if (!((bool)typeof(IEqualityComparer<>).MakeGenericType(propertyInfo.PropertyType)
                .GetMethod("Equals")
                .Invoke(propertyComparer, new object[] { leftValue, rightValue })))
            {
                // Create and publish the difference with its Type
            }
        }
        else
        {
            if (!Equals(leftValue, rightValue))
            {
                // Create and publish the difference with its Type
            }
        }
    }

    //return true if no differences are found
}
Run Code Online (Sandbox Code Playgroud)

Difference班级

public struct Difference
{
    public readonly string Property;

    public readonly DifferenceType Type;

    public readonly IExtractionable Expected;

    public readonly IExtractionable Actual;
}
Run Code Online (Sandbox Code Playgroud)

但可能这不是我想要的方式,因为我应该更准确地比较Field,考虑到每个Field都有Id,对于不同的形式也可以不同,我想更多地控制比较过程.对我来说,这听起来更像是一个差异工具.

所以我正在寻找良好的模式和相当不错的结构来将差异发布到客户端代码,这可以很容易地将其可视化?

Jev*_*sov 1

经过一番调查并比较不同的资源后,我实现了这样的算法。

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

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