Firstly, I saw IEqualityComparer for the anonymous type , and the answers there do not answer my question, for the obvious reason that I need IEqualityComparer not and IComparer for use with the Linq Distinct() method. I also checked other answers, and this does not match the solution ...
Problem
I have code to manipulate and write records from a DataTable
var glext = m_dtGLExt.AsEnumerable(); var cflist = (from c in glext orderby c.Field<string>(m_strpcCCType), c.Field<string>(m_strpcCC), c.Field<string>(m_strpcCCDesc), c.Field<string>(m_strpcCostItem) select new { CCType = c.Field<string>(m_strpcCCType), CC = c.Field<string>(m_strpcCC), CCDesc = c.Field<string>(m_strpcCCDesc), CostItem = c.Field<string>(m_strpcCostItem) }).Distinct();
but I need a separate method to be case insensitive. I am thrown using anonymous types.
Attempted Solution 1
If I had SomeClass that had specific objects, I could explicitly
public class SumObject { public string CCType { get; set; } public string CC { get; set; } public string CCDesc { get; set; } public string CostItem { get; set; } }
I could do it
List<SumObject> lso = new List<SumObject>() { new SumObject() { CCType = "1-OCC", CC = "300401", CCDesc = "Rooney", CostItem = "I477" }, new SumObject() { CCType = "1-OCC", CC = "300401", CCDesc = "Zidane", CostItem = "I677" }, new SumObject() { CCType = "1-OCC", CC = "300401", CCDesc = "Falcao", CostItem = "I470" }, }; var e = lso.Distinct(new SumObjectComparer());
Where
class SumObjectComparer : IEqualityComparer<SumObject> { public bool Equals(SumObject x, SumObject y) { if (Object.ReferenceEquals(x, y)) return true; if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) return false; return x.CCType.CompareNoCase(y.CCType) == 0 && x.CC.CompareNoCase(y.CC) == 0 && x.CCDesc.CompareNoCase(y.CCDesc) == 0 && x.CostItem.CompareNoCase(y.CostItem) == 0; } public int GetHashCode(SumObject o) { if (Object.ReferenceEquals(o, null)) return 0; int hashCCType = String.IsNullOrEmpty(o.CCType) ? 0 : o.CCType.ToLower().GetHashCode(); int hashCC = String.IsNullOrEmpty(o.CC) ? 0 : o.CC.ToLower().GetHashCode(); int hashCCDesc = String.IsNullOrEmpty(o.CCDesc) ? 0 : o.CCDesc.ToLower().GetHashCode(); int hashCostItem = String.IsNullOrEmpty(o.CostItem) ? 0 : o.CostItem.ToLower().GetHashCode(); return hashCCType ^ hashCC ^ hashCCDesc ^ hashCostItem; } }
However, using anonymous types in the above Linq query throws me away.
Attempted Solution 2
To try a different solution for this (and because I have the same problem elsewhere), I created the following general comparison class
public class GenericEqualityComparer<T> : IEqualityComparer<T> { Func<T, T, bool> compareFunction; Func<T, int> hashFunction; public GenericEqualityComparer(Func<T, T, bool> compareFunction, Func<T, int> hashFunction) { this.compareFunction = compareFunction; this.hashFunction = hashFunction; } public bool Equals(T x, T y) { return compareFunction(x, y); } public int GetHashCode(T obj) { return hashFunction(obj); } }
so that I can try to do
var comparer = new GenericEqualityComparer<dynamic>( (x, y) => { }, o => { });
but this returns the return value as IEnumerable<dynamic> , which in turn affects my upcoming use of cflist , so the join fails in the next request.
var cf = (from o in cflist join od in glext on new { o.CCType, o.CC, o.CCDesc, o.CostItem } equals new { CCType = od.Field<string>(m_strpcCCType), CC = od.Field<string>(m_strpcCC), CCDesc = od.Field<string>(m_strpcCCDesc), CostItem = od.Field<string>(m_strpcCostItem) } into c select new { ... }
I don't want to get into ugly casting to and from IEnumerable<T> due to the heavy use of this code ...
Question
Is there a way to create my IEquailityComparer for my anonymous types?
Thank you for your time.