我尝试使用Except
方法比较两个列表。但是当我这样做时,我得到一个错误说:
无法转换为'Systems.Collections.Generic.List<>'到'System.Linq.IQueryable<>'
“System.Collections.Generic.List<>不包含'Except'的定义和最佳扩展方法重载'System.Linq.Queryable.Except(System.Linq.IQueryable,System.Collections.GEneric.IEnumerable)'有一些无效的参数
当我尝试Intersect
时,我也经历过这种情况。我正在尝试比较已发送列表和结果列表(下面显示的代码和列表)并返回没有任何匹配项。所以当我用谷歌搜索如何这样做时,我遇到了Except方法以及Intersect。
public class Sent
{
public string Address;
public string Data;
}
public class Result
{
public string AddressOK;
public string DataOK;
}
var sent = new List<Sent>();
sent.Add(new Sent() { Address = linaddr1, Data = lindat1 });
var res = new List<Result>();
res.Add( new Result() { AddressOK = linaddr2, DataOK = lindat2 } );
//linaddr1 and 2, lindat1 and 2 contains the address and data shown in the list below
//taken from another part of the entire program
列表看起来像这样:
sent res
Address Data Address Data
04004C 55AA55 04004C 55AA55
040004 0720 040004 0720
040037 30
04004A FFFF 04004A FFFF
我只尝试过使用此代码:
var diff = sent.Except(res).ToList()
但正如我所提到的,它会导致上述错误。
答案 0 :(得分:2)
Sent
和Result
类型是不同的类型,但sent.Except(res)
期望它们是相同的。那是你的第一个错误。
以下是一个简单(但不正确)的修复:
var diff =
sent
.Except(res.Select(x => new Sent() { Address = x.AddressOK, Data = x.DataOK }))
.ToList();
即使这个编译并运行,它也不会删除重复项,因为Sent
不会覆盖GetHashCode
和Equals
,因此它只会比较引用而不是实际属性。
您可以实施GetHashCode
和Equals
,也可以创建IEqualityComparer<Sent>
以使其发挥作用。
IEqualityComparer<Sent>
实现可能如下所示:
public class SentEqualityComparer : IEqualityComparer<Sent>
{
public int GetHashCode(Sent sent)
{
return sent.Address.GetHashCode() ^ sent.Data.GetHashCode();
}
public bool Equals(Sent left, Sent right)
{
return (left.Address == right.Address) && (left.Data == right.Data);
}
}
你会像这样使用它:
var diff =
sent
.Except(
res.Select(x => new Sent() { Address = x.AddressOK, Data = x.DataOK }),
new SentEqualityComparer())
.ToList();
这可以按预期工作。
覆盖GetHashCode
和Equals
的另一个选项还有一个障碍。 GetHashCode
的结果不应该在对象的整个生命周期中发生变化,否则您无法在字典或依赖于哈希代码的任何其他数据结构中使用该对象。
因此,为了使其有效,您需要更改Address
&amp; Data
是只读的。
以下是您的Sent
类的实现,它将正常运行:
public sealed class Sent : IEquatable<Sent>
{
private readonly string _Address;
private readonly string _Data;
public string Address { get { return _Address; } }
public string Data { get { return _Data; } }
public Sent(string Address, string Data)
{
_Address = Address;
_Data = Data;
}
public override bool Equals(object obj)
{
if (obj is Sent)
return Equals((Sent)obj);
return false;
}
public bool Equals(Sent obj)
{
if (obj == null) return false;
if (!EqualityComparer<string>.Default.Equals(_Address, obj._Address)) return false;
if (!EqualityComparer<string>.Default.Equals(_Data, obj._Data)) return false;
return true;
}
public override int GetHashCode()
{
int hash = 0;
hash ^= EqualityComparer<string>.Default.GetHashCode(_Address);
hash ^= EqualityComparer<string>.Default.GetHashCode(_Data);
return hash;
}
}
答案 1 :(得分:1)
使用任何:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var sent = new List<Sent>()
{
new Sent { Address = "04004C", Data = "55AA55" },
new Sent { Address = "040004", Data = "0720" },
new Sent { Address = "040037", Data = "31" },
new Sent { Address = "04004A", Data = "FFFF" }
};
var res = new List<Result> () {
new Result { AddressOK = "04004C", DataOK = "55AA55" },
new Result { AddressOK = "040004", DataOK = "0721" },
new Result { AddressOK = "040038 ", DataOK = "31" },
new Result { AddressOK = "04004A", DataOK = "FFFF" }
};
var diff =
sent.Where (s => !res.Any (r => s.Address == r.AddressOK && s.Data == r.DataOK ));
foreach (var item in diff)
{
Console.WriteLine("{0} {1}", item.Address, item.Data);
}
}
}
public class Sent
{
public string Address;
public string Data;
}
public class Result
{
public string AddressOK;
public string DataOK;
}
输出:
040004 0720
040037 31
答案 2 :(得分:1)
@Kurisuchin 假设您有2个列表,并且在两个列表中都具有ID属性,您想基于该属性比较两个列表并将不匹配的项存储在第三个列表中。 在这种情况下,Linq Query可以提供帮助。
var结果= List2.Where(p =>!List1.Any(p2 => p2.ID == p.ID))。ToList();
答案 3 :(得分:0)
如果您习惯使用AOP组件来自动化实现IEquatable的手动代码,另一种方法是使用Equals.Fody:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var a = new Sent { Address = "04004C", Data = "55AA55" };
var b = new Sent { Address = "04004C", Data = "55AA55" };
Console.WriteLine(a.Equals(b)); // True with use of an AOP, False with no AOP
var sent = new List<Sent>() {
new Sent { Address = "04004C", Data = "55AA55" },
new Sent { Address = "040004", Data = "0720" },
new Sent { Address = "040037", Data = "31" },
new Sent { Address = "04004A", Data = "FFFF" }
};
var res = new List<Result>() {
new Result { AddressOK = "04004C", DataOK = "55AA55" },
new Result { AddressOK = "040004", DataOK = "0721" },
new Result { AddressOK = "040038 ", DataOK = "31" },
new Result { AddressOK = "04004A", DataOK = "FFFF" }
};
var diff =
sent.Except(
res.Select(r => new Sent { Address = r.AddressOK, Data = r.DataOK })
);
foreach (var item in diff)
Console.WriteLine("{0} {1}", item.Address, item.Data);
}
}
[Equals]
public class Sent
{
public string Address;
public string Data;
[CustomEqualsInternal]
bool CustomLogic(Sent other)
{
return other.Address == this.Address && other.Data == this.Data;
}
}
public class Result
{
public string AddressOK;
public string DataOK;
}
输出:
True
040004 0720
040037 31
如果你经常将结果映射到发送,你可以进一步缩短你的Linq查询代码..
var diff = sent.Except(res.Select(r => (Sent)r));
..通过自动将Result映射到Sent,使用隐式运算符:
[Equals]
public class Sent
{
public string Address;
public string Data;
[CustomEqualsInternal]
bool CustomLogic(Sent other)
{
return other.Address == this.Address && other.Data == this.Data;
}
public static implicit operator Sent(Result r)
{
return new Sent { Address = r.AddressOK, Data = r.DataOK };
}
}