如何使用方法语法使用LINQ和C#获得不同的结果

问题描述:

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

The following code still does not return a DISTINCT result set. The equivalent SQL I am trying to accomplish is 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;
    }

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

The problem you have is that you're creating distinct reference values (which will return different hashcodes), even if the properties inside each reference are equal, the actual references themselves are distinct.

// 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)

要解决难题,您应该:

  • Override the Object.GetHashCode() and the Object.Equals(Object) methods. Note that Distinct() ultimately uses the GetHashCode() to determine if something is distinct, but Equals(Object) and GetHashCode() should be overridden together.
    Guidelines for Overloading Equals() and Operator ==

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

public class Facility { public string ID { get; set; } public string Fac_Name { get; set; }

// 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();


此外,还需要注意一些其他事项:


Also, some other things to note:

  1. 您的命名不符合准则.请勿在属性名称中使用下划线,并且ID应为ID.
  2. 无论采用哪种方式,都应使用String.Equals(...)并指定StringComparison值.我只是在字符串上使用了==相等比较,以使文章简短易读.
  1. You're naming does not follow guidelines. Don't use underscores in property names, and ID should be Id.
  2. Whichever way you decide to go with, you should look into using String.Equals(...) and specify a StringComparison value. I just used == equality comparison on strings to keep the post short and readable.