用于Annoymous类型的IEqualityComparer

 yi品天下 发布于 2022-12-20 15:53

首先我看到IEqualityComparer是匿名类型,那里的答案没有回答我的问题,因为显而易见的原因是我需要一个IEqualityComparerIComparer用于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; }
}

我显然可以做到这一点

List lso = 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为我的匿名类型创建一个?

谢谢你的时间.

1 个回答
  • 有没有办法可以为我的匿名类型创建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);
    

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

    2022-12-20 15:58 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有