Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IEqualityComparer on different types

Tags:

c#

linq

Given two classes

class Contract
{
    public int ID {get; set;}
    // . . . 
}

class DBContract
{
    public int FromID {get; set;}
    // . . . 
}

And two IEnumerables

IEnumerable<Contract> ValidContracts = Application.GetContracts(//. . .
IEnumerable<DBContract> ExportedContracts = DBAdapter.GetRows(// . . .

I need to find intersection of theese IEnumerables. But how do I implement IEqualityComparer, if it only has one type argument?

like image 230
Dmitry Pavlushin Avatar asked May 15 '17 07:05

Dmitry Pavlushin


2 Answers

Why not use Where and Any instead? It is not as performant as Intersect, but it allows you to filter the way you want:

var list = ExportedContracts.Where(ec => ValidContracts.Any(vc => vc.ID == ec.FromID));

You can't use IEqualityComparer here since the object doesn't have any interface or base class (except object).

like image 120
Patrick Hofman Avatar answered Oct 23 '22 04:10

Patrick Hofman


In order to operate on a collection of mixed types an IEqualityComparer<T>'s type argument T must accept a common ancestor of all types in the collection.

Since Contract and DbContract appear unrelated, and do not share a common interface, you need to use object as the universal base class.

This may be too complicated for your purposes: perhaps you could implement intersection by ID as follows:

var commonIds = new HashSet<int>(contracts.Select(c => c.Id));
commonIds.IntersectWith(dbContracts.Select(dbc => dbc.FromId));

Now commonIds has IDs of the objects that you need. Running simple Wheres on both sides would produce two statically-typed parts of the intersection:

var commonContracts = contracts.Where(c => commonIds.Contains(c.Id));
var commonDbContracts = dbContracts.Where(dbc => commonIds.Contains(dbc.FromId));
like image 7
Sergey Kalinichenko Avatar answered Oct 23 '22 05:10

Sergey Kalinichenko