比较两个集合

发布于 2024-09-13 08:43:50 字数 217 浏览 1 评论 0原文

我有一个似乎常见的问题/模式。同一对象的两个集合。该对象具有许多属性和其中的一些嵌套对象。汽车有一个名为 id 的属性,它是唯一标识符。

我想找到 LINQ 方法来进行比较,其中包括:

  1. 一个集合中的项目,而不是另一个集合中的项目(反之亦然)
  2. 对于匹配的项目,是否有任何更改(更改将是所有属性的比较?(我只关心可设置的属性,我会为此使用反射吗?)

i have what seems like a common problem / pattern. two collections of the same object. The object has a number of properties and some nested objects within it. Car has a property called id which is the unique identifier.

I want to find the LINQ way to do a diff, which includes:

  1. Items in one collection and not the other (visa versa)
  2. For the items that match, are there any changes (changes would be a comparison of all properties? (i only care about settable properties, would i use reflection for this ?? )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

っ左 2024-09-20 08:43:50

您可以使用 Enumerable.Except() 方法。这使用比较器(默认的或您提供的比较器)来评估哪些对象同时存在于两个序列中或仅存在于一个序列中:

var sequenceA = new[] { "a", "e", "i", "o", "u" };
var sequenceB = new[] { "a", "b", "c" };

var sequenceDiff = sequenceA.Except( sequenceB );

如果要对两个序列执行完全析取(AB) union (BA) ,您必须使用:

var sequenceDiff = 
         sequenceA.Except( sequenceB ).Union( sequenceB.Except( sequenceA ) );

如果您有一个复杂类型,您可以为您的类型 T 编写一个 IComparer 并使用接受比较器的重载。

对于问题的第二部分,您需要滚动自己的实现来报告类型的哪些属性不同。.NET BCL 中没有直接内置任何内容。您必须决定该报告将采取什么形式?您如何识别和表达复杂类型中的差异?您当然可以为此使用反射......但如果您只处理单一类型,我会避免这种情况,并为其编写一个专门的差异实用程序。如果您要支持一系列类型,那么反射可能更有意义。

You can use the Enumerable.Except() method. This uses a comparer (either a default or one you supply) to evaluate which objects are in both sequences or just one:

var sequenceA = new[] { "a", "e", "i", "o", "u" };
var sequenceB = new[] { "a", "b", "c" };

var sequenceDiff = sequenceA.Except( sequenceB );

If you want to perform a complete disjunction of both sequences (A-B) union (B-A), you would have to use:

var sequenceDiff = 
         sequenceA.Except( sequenceB ).Union( sequenceB.Except( sequenceA ) );

If you have a complex type, you can write an IComparer<T> for your type T and use the overload that accepts the comparer.

For the second part of your question, you would need to roll your own implementation to report which properties of a type are different .. there's nothing built into the .NET BCL directly. You have to decide what form this reporting would take? How would you identify and express differences in a complex type? You could certainly use reflection for this ... but if you're only dealing with a single type I would avoid that, and write a specialized differencing utility just for it. If yo're going to support a borad range of types, then reflection may make more sense.

执着的年纪 2024-09-20 08:43:50

您已经收到了上半场的出色答复。正如 LBushkin 所解释的,后半部分不能直接由 BCL 课程完成。这是一个简单的方法,它遍历所有公共可设置属性(注意:在这些情况下,获取器可能不是公共的!)并将它们一一比较。如果两个对象 100% 相等,则返回 true。否则,它会提前爆发并返回 false:

static bool AllSettablePropertiesEqual<T>(T obj1, T obj2)
{
    PropertyInfo[] info1 = obj1.GetType().GetProperties(
        BindingFlags.Public |
        BindingFlags.SetProperty |
        BindingFlags.Instance);      // get public properties

    PropertyInfo[] info2 = obj2.GetType().GetProperties(
        BindingFlags.Public |
        BindingFlags.SetProperty |
        BindingFlags.Instance);      // get public properties

    // a loop is easier than linq here, and we can break out quick:
    for (var i = 0; i < info1.Length; i++)
    {
        var value1 = info1[i].GetValue(obj1, null);
        var value2 = info2[i].GetValue(obj2, null)
        if(value1 == null || value2 ==null)
        {
            if(value1 != value2)
                return false;
        }
        else if (!value1.Equals(value2))
        {
            return false;
        }
    }
    return true;
}

您可以轻松地将此方法添加到标准 LINQ 表达式中,如下所示:

var reallyReallyEqual = from itemA in listA
                        join itemB in listB 
                          on AllSettablePropertiesEqual(itemA, itemB)
                        select itemA;

You've already received an excellent answer for your first half. The second half, as LBushkin explains, cannot be done by BCL classes directly. Here's a simple method that goes through all public settable properties (note: it is possible that the gettor, in these cases, is not public!) and compares them one by one. If two objects are 100% equal, it will return true. Else, it will break out early and return false:

static bool AllSettablePropertiesEqual<T>(T obj1, T obj2)
{
    PropertyInfo[] info1 = obj1.GetType().GetProperties(
        BindingFlags.Public |
        BindingFlags.SetProperty |
        BindingFlags.Instance);      // get public properties

    PropertyInfo[] info2 = obj2.GetType().GetProperties(
        BindingFlags.Public |
        BindingFlags.SetProperty |
        BindingFlags.Instance);      // get public properties

    // a loop is easier than linq here, and we can break out quick:
    for (var i = 0; i < info1.Length; i++)
    {
        var value1 = info1[i].GetValue(obj1, null);
        var value2 = info2[i].GetValue(obj2, null)
        if(value1 == null || value2 ==null)
        {
            if(value1 != value2)
                return false;
        }
        else if (!value1.Equals(value2))
        {
            return false;
        }
    }
    return true;
}

You could easily add this method to a standard LINQ expression, like this:

var reallyReallyEqual = from itemA in listA
                        join itemB in listB 
                          on AllSettablePropertiesEqual(itemA, itemB)
                        select itemA;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文