-1

以下代码仍然不返回 DISTINCT 结果集。我试图完成的等效 SQL 是SELECT DISTINCT LEFT(Fac_Name, 6) AS ID, LEFT(Fac_Name, 3) AS Fac_Name

 public List<Facility> GetFacilities() {
        var facilities = new List<Facility>(); 
        facilities = _facilityRepository.GetAll().ToList();
        var facReturnList = 
            facilities.Where(x => x.Fac_Name = "Something")
                      .OrderBy(x => x.Fac_Name).ToList();

        var facReturnList2 = 
            facReturnList.Select(x => 
                new Facility { ID = x.Fac_Name.Substring(0, 6), 
                      Fac_Name = x.Fac_Name.Substring(0, 3) })
                .Distinct().ToList();
        return facReturnList2;
    }
4

3 回答 3

2

您遇到的问题是您正在创建不同的引用值(这将返回不同的哈希码),即使每个引用中的属性相等,实际引用本身也是不同的。

// fac1 and fac2 are the same reference, fac3 is a different reference.
var fac1 = new Facility { ID = "0", Fac_Name = "Hello" };
var fac2 = fac1;
var fac3 = new Facility { ID = "0", Fac_Name = "Hello" };

var facs = new List<Facility>() { fac1, fac2, fac3 };

foreach (var fac in facs.Distinct())
    Console.WriteLine("Id: {0} | Name: {1}", fac.ID, fac.Fac_Name);

// OUTPUT
// Id: 0 | Name: Hello (NOTE: This is the value of fac1/fac2)
// Id: 0 | Name: Hello (This is the value of fac3)

为了解决您的困境,您应该:

  • 覆盖Object.GetHashCode()Object.Equals(Object)方法。请注意,Distinct()最终使用 GetHashCode() 来确定某些内容是否不同,但Equals(Object)应该GetHashCode()一起覆盖。
    重载 Equals() 和运算符 == 的准则

    公共类设施 { 公共字符串 ID { 获取;放; } 公共字符串 Fac_Name { 获取;放; }

    // This is just a rough example.
    public override bool Equals(Object obj)
    {
        var fac = obj as Facility;
        if (fac == null) return false;
    
        if (Object.ReferenceEquals(this, fac)) return true;
    
        return (this.ID == fac.ID) && (this.Fac_Name == fac.Fac_Name);
    }
    
    public override int GetHashCode()
    {
        var hash = 13;
    
        if (!String.IsNullOrEmpty(this.ID))
            hash ^= ID.GetHashCode();
        if (!String.IsNullOrEmpty(this.Fac_Name))
            hash ^= Fac_Name.GetHashCode();
    
        return hash;
    }
    

    }



public class FacilityEqualityComparer : IEqualityComparer<Facility>
{
    public bool Equals(Facility x, Facility y)
    {
        return (x.ID == y.ID) && (x.Fac_Name == y.Fac_Name);
    }

    public int GetHashCode(Facility fac)
    {
        var hash = 13;

        if (!String.IsNullOrEmpty(this.ID))
            hash ^= ID.GetHashCode();
        if (!String.IsNullOrEmpty(this.Fac_Name))
            hash ^= Fac_Name.GetHashCode();

        return hash;
    }
}

var facReturnList2 = 
        facReturnList.Select(x => 
            new Facility { ID = x.Fac_Name.Substring(0, 6), 
                  Fac_Name = x.Fac_Name.Substring(0, 3) })
            .Distinct(new FacilityEqualityComparer()).ToList();

另外,还有一些需要注意的事项:

  1. 您的命名不遵循准则。属性名称中不要使用下划线,ID 应为 Id。
  2. 无论您决定采用哪种方式,都应该考虑使用String.Equals(...)并指定 StringComparison 值。我只是==在字符串上使用相等比较来保持帖子简短易读。
于 2013-03-08T18:52:54.910 回答
1

所以问题是该Enumerable.Distinct方法使用默认的相等比较器 - 它正在比较哈希码 - 所以无论属性值如何,它将是一个不同的列表。为该类型构建一个相等比较器:

public class FacilityEqualityComparer : IEqualityComparer<Facility>
{
    public bool Equals(Facility fac1, Facility fac2)
    {
        return fac1.ID.Equals(fac2.ID) && fac1.Fac_Name.Equals(fac2.Fac_Name);
    }

    public int GetHashCode(Facility fac)
    {
        string hCode = fac.ID + fac.Fac_Name;
        return hCode.GetHashCode();
    }
}

然后当你使用它时,像这样调用它:

var facReturnList2 = 
    facReturnList.Select(x => 
        new Facility { ID = x.Fac_Name.Substring(0, 6), 
              Fac_Name = x.Fac_Name.Substring(0, 3) })
        .Distinct(new FacilityEqualityComparer()).ToList();
return facReturnList2;
于 2013-03-08T18:53:53.663 回答
1

Distinct 使用默认的相等比较器来检查相等性。这意味着它正在寻找参考平等,这在您的情况下显然不会存在。

因此,您要么需要使用自定义IEqualityComparer(请参阅 的重载Distinct(),或者您可以复制Distinct()aGroupBy()和 a的功能First()

facReturnList.Select(x => 
                       new Facility { ID = x.Fac_Name.Substring(0, 6), 
                       Fac_Name = x.Fac_Name.Substring(0, 3) 
                     })
             .GroupBy(x => new{x.ID, x.Fac_Name})
             .Select(y => y.First())
             .ToList();

你也可以在你的Facility类中重写 Equals 方法:

public override bool Equals(System.Object obj)
{
    if (ReferenceEquals(null, obj)) return false;
    if (ReferenceEquals(this, obj)) return true;
    if (obj.GetType() != this.GetType()) return false;
    Facility objAsFacility = obj as Facility;
    return Equals(objAsFacility);
}

protected bool Equals(Facility other)
{
    if (other.Fac_Name == this.Fac_Name)
        return true;
    else return false;
}  

public override int GetHashCode()
{
    return this.Fac_Name.GetHashCode(); 
    //Or you might even want to this:
    //return (this.ID + this.Fac_Name).GetHashCode();
}

我可能会使用最重要的相等运算符方法。

于 2013-03-08T18:56:29.037 回答