c# – 用于Annoymous类型的IEqualityComparer

前端之家收集整理的这篇文章主要介绍了c# – 用于Annoymous类型的IEqualityComparer前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
首先我看到了 IEqualityComparer for anonymous type并且那里的答案没有回答我的问题,因为显而易见的原因是我需要IEqualityComparer而不是IComparer用于Linq的Distinct()方法.我也检查了其他答案,这些都没有解决方案……

问题

我有一些代码来操作和从DataTable中提取记录

  1. var glext = m_dtGLExt.AsEnumerable();
  2. var cflist =
  3. (from c in glext
  4. orderby c.Field<string>(m_strpcCCType),c.Field<string>(m_strpcCC),c.Field<string>(m_strpcCCDesc),c.Field<string>(m_strpcCostItem)
  5. select new
  6. {
  7. CCType = c.Field<string>(m_strpcCCType),CC = c.Field<string>(m_strpcCC),CCDesc = c.Field<string>(m_strpcCCDesc),CostItem = c.Field<string>(m_strpcCostItem)
  8. }).Distinct();

但是我需要使用不同的方法来区分大小写.这里扔我的是使用匿名类型.

尝试解决方案1

如果我有SomeClass有明显的具体对象我可以做

  1. public class SumObject
  2. {
  3. public string CCType { get; set; }
  4. public string CC { get; set; }
  5. public string CCDesc { get; set; }
  6. public string CostItem { get; set; }
  7. }

我显然可以做到这一点

  1. List<SumObject> lso = new List<SumObject>()
  2. {
  3. new SumObject() { CCType = "1-OCC",CC = "300401",CCDesc = "Rooney",CostItem = "I477" },new SumObject() { CCType = "1-OCC",CCDesc = "Zidane",CostItem = "I677" },CCDesc = "Falcao",CostItem = "I470" },};
  4. var e = lso.Distinct(new SumObjectComparer()); // Great :]

哪里

  1. class SumObjectComparer : IEqualityComparer<SumObject>
  2. {
  3. public bool Equals(SumObject x,SumObject y)
  4. {
  5. if (Object.ReferenceEquals(x,y))
  6. return true;
  7. if (Object.ReferenceEquals(x,null) || Object.ReferenceEquals(y,null))
  8. return false;
  9. return x.CCType.CompareNoCase(y.CCType) == 0 &&
  10. x.CC.CompareNoCase(y.CC) == 0 &&
  11. x.CCDesc.CompareNoCase(y.CCDesc) == 0 &&
  12. x.CostItem.CompareNoCase(y.CostItem) == 0;
  13. }
  14.  
  15. public int GetHashCode(SumObject o)
  16. {
  17. if (Object.ReferenceEquals(o,null))
  18. return 0;
  19. int hashCCType = String.IsNullOrEmpty(o.CCType) ?
  20. 0 : o.CCType.ToLower().GetHashCode();
  21. int hashCC = String.IsNullOrEmpty(o.CC) ?
  22. 0 : o.CC.ToLower().GetHashCode();
  23. int hashCCDesc = String.IsNullOrEmpty(o.CCDesc) ?
  24. 0 : o.CCDesc.ToLower().GetHashCode();
  25. int hashCostItem = String.IsNullOrEmpty(o.CostItem) ?
  26. 0 : o.CostItem.ToLower().GetHashCode();
  27. return hashCCType ^ hashCC ^ hashCCDesc ^ hashCostItem;
  28. }
  29. }

但是,在上面的Linq查询中使用匿名类型会让我失望.

尝试解决方案2

为了尝试另一个解决方案(因为我在其他地方有相同的问题),我生成了以下通用比较器类

  1. public class GenericEqualityComparer<T> : IEqualityComparer<T>
  2. {
  3. Func<T,T,bool> compareFunction;
  4. Func<T,int> hashFunction;
  5.  
  6. public GenericEqualityComparer(Func<T,bool> compareFunction,Func<T,int> hashFunction)
  7. {
  8. this.compareFunction = compareFunction;
  9. this.hashFunction = hashFunction;
  10. }
  11.  
  12. public bool Equals(T x,T y) { return compareFunction(x,y); }
  13. public int GetHashCode(T obj) { return hashFunction(obj); }
  14. }

所以我可以尝试做

  1. var comparer = new GenericEqualityComparer<dynamic>(
  2. (x,y) => { /* My equality stuff */ },o => { /* My hash stuff */ });

但是这会将返回的值转换为IEnumerable< dynamic>这反过来影响我即将使用的cflist,因此在以下查询中,连接失败.

  1. var cf =
  2. (from o in cflist
  3. join od in glext
  4. on new { o.CCType,o.CC,o.CCDesc,o.CostItem } equals new
  5. {
  6. CCType = od.Field<string>(m_strpcCCType),CC = od.Field<string>(m_strpcCC),CCDesc = od.Field<string>(m_strpcCCDesc),CostItem = od.Field<string>(m_strpcCostItem)
  7. }
  8. into c
  9. select new { ... }

由于大量使用此代码,我不想进入IEnumerable< T> s进行丑陋的转换…

有没有办法可以为我的匿名类型创建IEquailityComparer?

谢谢你的时间.

解决方法

Is there a way I can create my an IEquailityComparer for my anonymous types?

当然.您只需要使用类型推断.例如,你可以有类似的东西:

  1. public static class InferredEqualityComparer
  2. {
  3. public static IEqualityComparer<T> Create<T>(
  4. IEnumerable<T> example,bool> equalityCheck,int> hashCodeProvider)
  5. {
  6. return new EqualityComparerImpl<T>(equalityCheck,hashCodeProvider);
  7. }
  8.  
  9. private sealed class EqualityComparerImpl<T> : IEqualityComparer<T>
  10. {
  11. // Implement in the obvIoUs way,remembering the delegates and
  12. // calling them appropriately.
  13. }
  14. }

然后:

  1. var glext = m_dtGLExt.AsEnumerable();
  2. var query = from c in glext
  3. orderby ...
  4. select new { ... };
  5. var comparer = InferredEqualityComparer.Create(query,(x,y) => { ... },o => { ... }
  6. );
  7. var distinct = query.Distinct(comparer);

基本上,该方法的第一个参数仅用于类型推断,因此编译器可以计算出用于lambda表达式参数的类型.

您可以通过创建匿名类型的示例来提前创建比较器:

  1. var sample = new[] { new { ... } };
  2. var comparer = InferredExqualityComparer.Create(sample,...);
  3. var distinct = (... query here ... ).Distinct(comparer);

但是每当你改变查询时,你也必须改变样本.

猜你在找的C#相关文章