首先我看到IEqualityComparer是匿名类型,那里的答案没有回答我的问题,因为显而易见的原因是我需要一个IEqualityComparer
不IComparer
用于Linq的Distinct()
方法.我也检查了其他答案,这些都没有解决方案......
问题
我有一些代码来操纵和从中提取记录 DataTable
var glext = m_dtGLExt.AsEnumerable(); var cflist = (from c in glext orderby c.Field(m_strpcCCType), c.Field (m_strpcCC), c.Field (m_strpcCCDesc), c.Field (m_strpcCostItem) select new { CCType = c.Field (m_strpcCCType), CC = c.Field (m_strpcCC), CCDesc = c.Field (m_strpcCCDesc), CostItem = c.Field (m_strpcCostItem) }).Distinct();
但是我需要使用不同的方法来区分大小写.这里扔我的是使用匿名类型.
尝试解决方案1
如果我有SomeClass
具体的物体,我显然可以做到
public class SumObject { public string CCType { get; set; } public string CC { get; set; } public string CCDesc { get; set; } public string CostItem { get; set; } }
我显然可以做到这一点
Listlso = new List () { 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()); // Great :]
哪里
class SumObjectComparer : IEqualityComparer{ 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; } }
但是,在上面的Linq查询中使用匿名类型会让我失望.
尝试解决方案2
为了尝试另一个解决方案(因为我在其他地方有相同的问题),我生成了以下通用比较器类
public class GenericEqualityComparer: IEqualityComparer { Func compareFunction; Func hashFunction; public GenericEqualityComparer(Func compareFunction, Func 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); } }
所以我可以尝试做
var comparer = new GenericEqualityComparer( (x, y) => { /* My equality stuff */ }, o => { /* My hash stuff */ });
但这会转换返回的值,IEnumerable
这反过来影响我即将使用的cflist
,以便在后面的查询中join
失败.
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(m_strpcCCType), CC = od.Field (m_strpcCC), CCDesc = od.Field (m_strpcCCDesc), CostItem = od.Field (m_strpcCostItem) } into c select new { ... }
IEnumerable
由于大量使用此代码,我不想进入丑陋的演员阵容......
题
有没有办法可以IEquailityComparer
为我的匿名类型创建一个?
谢谢你的时间.
有没有办法可以为我的匿名类型创建IEquailityComparer?
当然.您只需要使用类型推断.例如,你可以有类似的东西:
public static class InferredEqualityComparer { public static IEqualityComparer<T> Create<T>( IEnumerable<T> example, Func<T, T, bool> equalityCheck, Func<T, int> hashCodeProvider) { return new EqualityComparerImpl<T>(equalityCheck, hashCodeProvider); } private sealed class EqualityComparerImpl<T> : IEqualityComparer<T> { // Implement in the obvious way, remembering the delegates and // calling them appropriately. } }
然后:
var glext = m_dtGLExt.AsEnumerable(); var query = from c in glext orderby ... select new { ... }; var comparer = InferredEqualityComparer.Create(query, (x, y) => { ... }, o => { ... } ); var distinct = query.Distinct(comparer);
基本上,该方法的第一个参数仅用于类型推断,因此编译器可以计算出用于lambda表达式参数的类型.
您可以通过创建匿名类型的示例来提前创建比较器:
var sample = new[] { new { ... } }; var comparer = InferredExqualityComparer.Create(sample, ...); var distinct = (... query here ... ).Distinct(comparer);
但是,每当你更改查询时,你也必须更改样本.