简体   繁体   中英

Correct way to create a custom comparer for linq join

I have some problems creating a custom comparer to be used in linq.join. I'm not very expert in linq, so I probably misunderstood join function behavior.

This is my code. I want to perfor a simple join between those two lists:

List<MyObj> operand1Data = new List<MyObj>()
{
    new MyObj() { Var = "1var1", Year = 0 },
    new MyObj() { Var = "1var2", Year = 2018 },
};

List<MyObj> operand2Data = new List<MyObj>()
{
    new MyObj() { Var = "2var1", Year = 2018 },
    new MyObj() { Var = "2var2", Year = 2019 },
    new MyObj() { Var = "2var3", Year = 2020 },
};

var result= operand1Data.Join(operand2Data, x => x.Year, y => y.Year, (x, y) => x.Var + y.Var, new TestComparer()).ToList();

The problem is that I want 0 to match with every element in the other list, so I came up with this custom comparer:

public class TestComparer : IEqualityComparer<int>
{
    public bool Equals(int x, int y)
    {
        if (x == 0 || y == 0)
        {
            return true;
        }
        else
        {
            return x.Equals(y);
        }
    }

    public int GetHashCode(int obj)
    {
        return 1;
    }
}

This does not work. The result only contains:

"1var12var3"
"1var22var1"

and what I expected was:

"1var12var1"
"1var12var2"
"1var12var3"
"1var22var1"

What am I missing? Can someone help me fixing this? Thanks for your help.

i've tried your code and i guess that LINQ Join have a default filter that gets applied before the custom IEqualityComparer<T> .

With a log inside the Equals(x,y) , this is what i got:

 "Equality test x:2018 y:2019 = False" "Equality test x:2019 y:2020 = False" "Equality test x:2018 y:2020 = False" "Equality test x:2020 y:0 = True" "Equality test x:2020 y:2018 = False" "Equality test x:2019 y:2018 = False" "Equality test x:2018 y:2018 = True"

You see? Only one "zero" equality check.

So, my suggestion is to use the linq query-syntax with a cross join, then filter elements by where conditions:

var result = from o1 in operand1Data
             from o2 in operand2Data
             where o1.Year == 0 || o2.Year == 0 || o1.Year == o2.Year
             select o1.Var + o2.Var;

The result is exactly what you're looking for:

 "1var12var1" "1var12var2" "1var12var3" "1var22var1"

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM