给出两个班级
class Contract
{
public int ID {get; set;}
// . . .
}
class DBContract
{
public int FromID {get; set;}
// . . .
}
两个IEnumerables
IEnumerable<Contract> ValidContracts = Application.GetContracts(//. . .
IEnumerable<DBContract> ExportedContracts = DBAdapter.GetRows(// . . .
我需要找到这些IEnumerables的交集。但是,如果它只有一个类型参数,我该如何实现IEqualityComparer呢?
答案 0 :(得分:6)
为了对混合类型的集合进行操作,IEqualityComparer<T>
类型的参数T
必须接受集合中所有类型的共同祖先。
由于Contract
和DbContract
似乎不相关,并且不共享公共接口,因此您需要使用object
作为通用基类。
这可能对您的目的来说太复杂了:也许您可以通过ID
实现交集,如下所示:
var commonIds = new HashSet<int>(contracts.Select(c => c.Id));
commonIds.IntersectWith(dbContracts.Select(dbc => dbc.FromId));
现在commonIds
拥有您需要的IDs
个对象。在两侧运行简单的Where
将产生两个静态类型的交叉部分:
var commonContracts = contracts.Where(c => commonIds.Contains(c.Id));
var commonDbContracts = dbContracts.Where(dbc => commonIds.Contains(dbc.FromId));
答案 1 :(得分:3)
为什么不使用Where
和Any
呢?它不像Intersect
那样具有效果,但它允许您按照您想要的方式进行过滤:
var list = ExportedContracts.Where(ec => ValidContracts.Any(vc => vc.ID == ec.FromID));
您不能在此使用IEqualityComparer
,因为该对象没有任何接口或基类(object
除外)。
答案 2 :(得分:2)
我会为Contract
/ DBContract
创建一个临时容器:
public class ContractDbContract
{
public Contract Contract;
public DBContract DBContract;
public int ID
{
get
{
return Contract?.ID ?? DBContract.FromID;
}
}
}
IEnumerable<Contract> ValidContracts = Application.GetContracts(//. . .
IEnumerable<DBContracts> ExportedContracts = DBAdapter.GetRows(// . . .
var validContracts2 = ValidContracts.Select(x => new ContractDbContract { Contract = x });
var exportedContracts2 = ExportedContracts.Select(x => new ContractDbContract { DBContract = x });
现在您可以根据需要与validContracts2
和exportedContracts2
相交,然后很容易提取&#34;提取&#34;来自Contract
DBContract
/ ContractDBContract
答案 3 :(得分:1)
如果他们无法让他们实现相同的界面,例如IDBContract
并提供自定义IEqualityComparer<IDBContract>
,则您无法使用Intersect
,但可以使用Enumerable.Join
:< / p>
var commonContracts = from c in ValidContracts
join ec in ExportedContracts on c.ID equals ec.FromID
select new { contract = c, exportedContract = ec };
Join
也使用基于集合的方法,因此它比Where
更有效:
答案 4 :(得分:0)
您可以自己实现Intersect
,但无需使用HashSet
,就像这样:
public static IEnumerable<TFirst> Intersect<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second,
Func<TFirst, TSecond, bool> comparerFunc)
{
return first.Where(firstItem => second.Any(secondItem => comparerFunc(firstItem, secondItem)));
}
并像这样使用它:
IEnumerable<Contract> ValidContracts = Application.GetContracts(//. . .
IEnumerable<DBContract> ExportedContracts = DBAdapter.GetRows(// . . .
var intersect = ValidContracts.Intersect(ExportedContracts, (contract, dbContract) => contract.ID == dbContract.FromID);