Я думаю, что это может помочь вам (я добавляю do tnet URL скрипты , чтобы вы могли поиграть с ним)
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public class ExampleClass
{
public string FieldX { set; get; }
public string FieldY { set; get; }
public string FieldZ { set; get; }
public string FieldA { set; get; }
public string FieldB { set; get; }
public string FieldC { set; get; }
}
public class IncludeBlankComparer : IEqualityComparer<(string a, string b, string c)>
{
public static bool IsBlank(string s) => string.IsNullOrEmpty(s);
private static bool IsMatchOrBlankMatch(string left, string right) => left == right || IsBlank(left) || IsBlank(right);
public bool Equals((string a, string b, string c) first, (string a, string b, string c) second)
{
if (first == second) return true;
return IsMatchOrBlankMatch(first.a, second.a)
&& IsMatchOrBlankMatch(first.b, second.b)
&& IsMatchOrBlankMatch(first.c, second.c);
}
public int GetHashCode((string a, string b, string c) s) => 0;
}
public static void Main()
{
var obj1 = new ExampleClass{
FieldA = "AAA",
FieldB = "BBB",
FieldC = "CCC",
FieldX = "Matched",
FieldY = "Matched",
FieldZ = "Matched"
};
var obj2 = new ExampleClass{
FieldA = "ada a",
FieldB = "BBBada ",
FieldC = "CCadasd aC",
FieldX = "Matched",
FieldY = "Matched",
FieldZ = "Matched"
};
var obj3 = new ExampleClass{
FieldA = "AfsfAA",
FieldB = "BBsfsfB",
FieldC = "CsfsghsCC",
FieldX = "",
FieldY = "Matched",
FieldZ = "Matched"
};
var obj4 = new ExampleClass{
FieldA = "AAA",
FieldB = "BBB",
FieldC = "CCC",
FieldX = "Not Matched",
FieldY = "Not Matched",
FieldZ = "Matched"
};
var list = new List<ExampleClass>(new ExampleClass[] { obj1, obj2, obj3, obj4 } );
var grp = list.GroupBy(x => ( x.FieldX, x.FieldY, x.FieldZ ), new IncludeBlankComparer());
grp.Dump();
}
}
Объяснение : Вы можете передать пользовательский компаратор в метод GroupBy. Конечно, компаратор должен обрабатывать сравнение тех же типов, что и ключ. Обратите внимание, что я изменил ключевой селектор с анонимного класса (в котором я не могу ссылаться на внутренних членов) на кортеж (в котором я могу).
Примечание : это решение будет работать только с ключом кортежа, который имеет 3 строковых части.
Примечание 2 : из-за хакерской природы этого решения мне пришлось использовать GetHashCode() => 0
. Это будет работать, поскольку реализация поиска сравнивает как на равенство, так и на равенство хеш-кодов, и не нарушит реализацию GroupBy, однако само по себе это не "чистое" решение.