首先我看到了
IEqualityComparer for anonymous type并且那里的答案没有回答我的问题,因为显而易见的原因是我需要IEqualityComparer而不是IComparer用于Linq的Distinct()方法.我也检查了其他答案,这些都没有解决方案……
问题
- 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();
但是我需要使用不同的方法来区分大小写.这里扔我的是使用匿名类型.
尝试解决方案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; }
- }
我显然可以做到这一点
- List<SumObject> lso = new List<SumObject>()
- {
- new SumObject() { CCType = "1-OCC",CC = "300401",CCDesc = "Rooney",CostItem = "I477" },new SumObject() { CCType = "1-OCC",CCDesc = "Zidane",CostItem = "I677" },CCDesc = "Falcao",CostItem = "I470" },};
- var e = lso.Distinct(new SumObjectComparer()); // Great :]
哪里
- 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;
- }
- }
但是,在上面的Linq查询中使用匿名类型会让我失望.
尝试解决方案2
为了尝试另一个解决方案(因为我在其他地方有相同的问题),我生成了以下通用比较器类
- public class GenericEqualityComparer<T> : IEqualityComparer<T>
- {
- Func<T,T,bool> compareFunction;
- Func<T,int> hashFunction;
- public GenericEqualityComparer(Func<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); }
- }
所以我可以尝试做
- var comparer = new GenericEqualityComparer<dynamic>(
- (x,y) => { /* My equality stuff */ },o => { /* My hash stuff */ });
但是这会将返回的值转换为IEnumerable< dynamic>这反过来影响我即将使用的cflist,因此在以下查询中,连接失败.
- 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 { ... }
由于大量使用此代码,我不想进入IEnumerable< T> s进行丑陋的转换…
题
有没有办法可以为我的匿名类型创建IEquailityComparer?
谢谢你的时间.
解决方法
Is there a way I can create my an IEquailityComparer for my anonymous types?
当然.您只需要使用类型推断.例如,你可以有类似的东西:
- public static class InferredEqualityComparer
- {
- public static IEqualityComparer<T> Create<T>(
- IEnumerable<T> example,bool> equalityCheck,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);
但是每当你改变查询时,你也必须改变样本.