IEqualityComparer对不同类型的

时间:2017-05-15 07:39:38

标签: c# linq

给出两个班级

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呢?

5 个答案:

答案 0 :(得分:6)

为了对混合类型的集合进行操作,IEqualityComparer<T>类型的参数T必须接受集合中所有类型的共同祖先。

由于ContractDbContract似乎不相关,并且不共享公共接口,因此您需要使用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)

为什么不使用WhereAny呢?它不像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 });

现在您可以根据需要与validContracts2exportedContracts2相交,然后很容易提取&#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更有效:

Why is LINQ JOIN so much faster than linking with 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);