C# 快速获取两个列表之间差异的方法<&燃气轮机;物体

C# 快速获取两个列表之间差异的方法<&燃气轮机;物体,c#,list,C#,List,如何使itemsToRemove仅包含“bar-one”,而itemsToAdd仅包含“bar-five” 我试图使用“除外”,但显然我用错了 var oldList = new List<Foo>(); oldList.Add(new Foo(){ Bar = "bar one"}); oldList.Add(new Foo(){ Bar = "bar two"}); oldList.Add(new Foo(){ Bar = "bar three"}); oldList.Add(n

如何使
itemsToRemove
仅包含“bar-one”,而
itemsToAdd
仅包含“bar-five”

我试图使用“除外”,但显然我用错了

var oldList = new List<Foo>();
oldList.Add(new Foo(){ Bar = "bar one"});
oldList.Add(new Foo(){ Bar = "bar two"});
oldList.Add(new Foo(){ Bar = "bar three"});
oldList.Add(new Foo(){ Bar = "bar four"});



var newList = new List<Foo>();
newList.Add(new Foo(){ Bar = "bar two"});
newList.Add(new Foo(){ Bar = "bar three"});
newList.Add(new Foo(){ Bar = "bar four"});
newList.Add(new Foo(){ Bar = "bar five"});


var itemsToRemove = oldList.Except(newList);    // should only contain "bar one"
var itemsToAdd = newList.Except(oldList);    // should only contain "bar one"


foreach(var item in itemsToRemove){
    Console.WriteLine(item.Bar + " removed");
    // currently says 
    // bar one removed
    // bar two removed
    // bar three removed
    // bar four removed
}


foreach(var item in itemsToAdd){
    Console.WriteLine(item.Bar + " added");
    // currently says 
    // bar two added
    // bar three added
    // bar four added
    // bar five added
}
var oldList=新列表();
Add(newfoo(){Bar=“Bar one”});
Add(newfoo(){Bar=“Bar two”});
Add(newfoo(){Bar=“Bar three”});
Add(newfoo(){Bar=“Bar four”});
var newList=新列表();
Add(newfoo(){Bar=“Bar two”});
Add(newfoo(){Bar=“Bar three”});
Add(newfoo(){Bar=“Bar four”});
Add(newfoo(){Bar=“Bar-five”});
var itemsToRemove=oldList.Except(newList);//应仅包含“第一栏”
var itemsToAdd=newList.Except(oldList);//应仅包含“第一栏”
foreach(itemsToRemove中的变量项){
控制台写入线(item.Bar+“已删除”);
//现在说
//一号杆已拆除
//删除第二条
//三号杆已拆除
//删除第四栏
}
foreach(itemsToAdd中的var项){
控制台写入线(item.Bar+“添加”);
//现在说
//增加了第二栏
//增加了第三栏
//增加了第四栏
//增加第五栏
}

这是因为您正在比较类型为
Foo
的对象,而不是类型为
string
的属性栏。尝试:

var itemsToRemove = oldList.Select(i => i.Bar).Except(newList.Select(i => i.Bar));
var itemsToAdd = newList.Select(i => i.Bar).Except(oldList.Select(i => i.Bar));

这是因为您正在比较类型为
Foo
的对象,而不是类型为
string
的属性栏。尝试:

var itemsToRemove = oldList.Select(i => i.Bar).Except(newList.Select(i => i.Bar));
var itemsToAdd = newList.Select(i => i.Bar).Except(oldList.Select(i => i.Bar));

Except
将使用相关对象的默认
Equals
GetHashCode
方法来定义对象的“相等”,除非您提供了自定义比较器(尚未提供)。在这种情况下,这将比较对象的引用,而不是它们的
Bar

一个选项是创建一个比较
属性的
IEqualityComparer
,而不是对对象本身的引用

public class FooComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        if (x == null ^ y == null)
            return false;
        if (x == null && y == null)
            return true;
        return x.Bar == y.Bar;
    }

    public int GetHashCode(Foo obj)
    {
        if (obj == null)
            return 0;
        return obj.Bar.GetHashCode();
    }
}
这使我们能够写:

var itemsToRemove = oldList.ExceptBy(newList, foo => foo.Bar);
var itemsToAdd = newList.ExceptBy(oldList, foo => foo.Bar);

Except
将使用相关对象的默认
Equals
GetHashCode
方法来定义对象的“相等”,除非您提供了自定义比较器(尚未提供)。在这种情况下,这将比较对象的引用,而不是它们的
Bar

一个选项是创建一个比较
属性的
IEqualityComparer
,而不是对对象本身的引用

public class FooComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        if (x == null ^ y == null)
            return false;
        if (x == null && y == null)
            return true;
        return x.Bar == y.Bar;
    }

    public int GetHashCode(Foo obj)
    {
        if (obj == null)
            return 0;
        return obj.Bar.GetHashCode();
    }
}
这使我们能够写:

var itemsToRemove = oldList.ExceptBy(newList, foo => foo.Bar);
var itemsToAdd = newList.ExceptBy(oldList, foo => foo.Bar);

您的逻辑是合理的,但比较两个类的默认行为是按引用进行。由于您可以有效地创建两个包含8个不同对象(无论其内容如何)的列表,因此不会有两个相等的对象

但是,您可以使用。例如:

public class FooEqualityComparer : IEqualityComparer<Foo> 
{
    public bool Equals(Foo left, Foo right) 
    {
        if(left == null && right == null) return true;

        return left != null && right != null && left.Bar == right.Bar;
    }

    public int GetHashCode(Foo item)
    {
        return item != null ? item.Bar.GetHashcode() : 0;
    }
}

// In your code

var comparer = new FooEqualityComparer();
var itemsToRemove = oldList.Except(newList, comparer ); 
var itemsToAdd = newList.Except(oldList, comparer); 
公共类FooEqualityComparer:IEqualityComparer
{
公共布尔等于(左,右)
{
if(left==null&&right==null)返回true;
返回left!=null&&right!=null&&left.Bar==right.Bar;
}
public int GetHashCode(Foo项)
{
返回项!=null?item.Bar.GetHashcode():0;
}
}
//在代码中
var comparer=new FooEqualityComparer();
var itemsToRemove=oldList.Except(newList,comparer);
var itemsToAdd=newList.Except(oldList,comparer);

您的逻辑是正确的,但是比较两个类的默认行为是按引用进行。由于您可以有效地创建两个包含8个不同对象(无论其内容如何)的列表,因此不会有两个相等的对象

但是,您可以使用。例如:

public class FooEqualityComparer : IEqualityComparer<Foo> 
{
    public bool Equals(Foo left, Foo right) 
    {
        if(left == null && right == null) return true;

        return left != null && right != null && left.Bar == right.Bar;
    }

    public int GetHashCode(Foo item)
    {
        return item != null ? item.Bar.GetHashcode() : 0;
    }
}

// In your code

var comparer = new FooEqualityComparer();
var itemsToRemove = oldList.Except(newList, comparer ); 
var itemsToAdd = newList.Except(oldList, comparer); 
公共类FooEqualityComparer:IEqualityComparer
{
公共布尔等于(左,右)
{
if(left==null&&right==null)返回true;
返回left!=null&&right!=null&&left.Bar==right.Bar;
}
public int GetHashCode(Foo项)
{
返回项!=null?item.Bar.GetHashcode():0;
}
}
//在代码中
var comparer=new FooEqualityComparer();
var itemsToRemove=oldList.Except(newList,comparer);
var itemsToAdd=newList.Except(oldList,comparer);

在数据对象上实现IComparable;我想你被参照物的比较给咬了。如果您将Foo更改为string,则代码可以正常工作

        var oldList = new List<string>();
        oldList.Add("bar one");
        oldList.Add("bar two");
        oldList.Add("bar three");
        oldList.Add("bar four");

        var newList = new List<string>();
        newList.Add("bar two");
        newList.Add("bar three");
        newList.Add("bar four");
        newList.Add("bar five");

        var itemsToRemove = oldList.Except(newList);    // should only contain "bar one"
        var itemsToAdd = newList.Except(oldList);    // should only contain "bar one"

        foreach (var item in itemsToRemove)
        {
            Console.WriteLine(item + " removed");
        }


        foreach (var item in itemsToAdd)
        {
            Console.WriteLine(item + " added");
        }
var oldList=新列表();
添加(“第一栏”);
添加(“第二栏”);
添加(“第三栏”);
添加(“第四栏”);
var newList=新列表();
新增列表。添加(“第二栏”);
新增列表。添加(“第三栏”);
新增列表。添加(“第四栏”);
新增列表。添加(“第五栏”);
var itemsToRemove=oldList.Except(newList);//应仅包含“第一栏”
var itemsToAdd=newList.Except(oldList);//应仅包含“第一栏”
foreach(itemsToRemove中的变量项)
{
控制台写入线(项目+“删除”);
}
foreach(itemsToAdd中的var项)
{
控制台写入线(项目+“添加”);
}

在数据对象上实现IComparable;我想你被参照物的比较给咬了。如果您将Foo更改为string,则代码可以正常工作

        var oldList = new List<string>();
        oldList.Add("bar one");
        oldList.Add("bar two");
        oldList.Add("bar three");
        oldList.Add("bar four");

        var newList = new List<string>();
        newList.Add("bar two");
        newList.Add("bar three");
        newList.Add("bar four");
        newList.Add("bar five");

        var itemsToRemove = oldList.Except(newList);    // should only contain "bar one"
        var itemsToAdd = newList.Except(oldList);    // should only contain "bar one"

        foreach (var item in itemsToRemove)
        {
            Console.WriteLine(item + " removed");
        }


        foreach (var item in itemsToAdd)
        {
            Console.WriteLine(item + " added");
        }
var oldList=新列表();
添加(“第一栏”);
添加(“第二栏”);
添加(“第三栏”);
添加(“第四栏”);
var newList=新列表();
新增列表。添加(“第二栏”);
新增列表。添加(“第三栏”);
新增列表。添加(“第四栏”);
新增列表。添加(“第五栏”);
var itemsToRemove=oldList.Except(newList);//应仅包含“第一栏”
var itemsToAdd=newList.Except(oldList);//应仅包含“第一栏”
foreach(itemsToRemove中的变量项)
{
控制台写入线(项目+“删除”);
}
foreach(itemsToAdd中的var项)
{
控制台写入线(项目+“添加”);
}
这主要是一段关于