如何使用方法语法使用LINQ和C#获得不同的结果
以下代码仍然不会返回DISTINCT结果集。我试图完成的等效SQL是SELECT DISTINCT LEFT(Fac_Name, 6) AS ID, LEFT(Fac_Name, 3) AS Fac_Name
如何使用方法语法使用LINQ和C#获得不同的结果
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;
}
你的问题是,你正在创建不同的参考值(这将返回不同的散列码),即使每个参考里面的属性是相等的,实际的引用本身是不同的。
// 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()
应该一起覆盖。
Guidelines for Overloading Equals() and Operator ==公共类基金 { 公共字符串ID {获得;组; } public string Fac_Name {get;组; }
// 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; }
}
- 提供自定义
IEqualityComparer<T>
。
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();
此外,一些其他的事情需要注意:
- 你命名不遵循的准则。不要在属性名称中使用下划线,并且ID应该是Id。
- 无论您决定使用哪种方式,您都应该考虑使用
String.Equals(...)
并指定一个StringComparison值。我只是使用==
字符串的平等比较来保持文章简短和可读性。
所以问题是,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;
不同的用法默认的相等比较,以检查是否相等。这意味着它正在寻找参考平等,这显然不会在你的情况。
所以你要么需要使用自定义IEqualityComparer
(参见过载Distinct()
,或者你可以用GroupBy()
复制的Distinct()
功能和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();
你也可以重载equals方法在Facility
类:
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();
}
我可能会与压倒一切的平等操作方法去
James当你调试代码时,当你把鼠标悬停在每一个上面时,你会发现下面的'var'变量。你得到重复吗?任何数据......等等......? – MethodMan 2013-03-08 18:52:53
你已经发布了这个确切的问题不到半个小时前,并得到了一些答案。您不应该因为对现有答案不满意而重新发布相同的问题。如果答案没有解决您的问题,您也不应将答案标记为“答案”。 – Servy 2013-03-08 18:56:17
@Servy,前面的问题与我得到的匿名类型以及如何让它返回我需要的类型有关。这当然与相同的一组代码有关,但具体涉及如何获得不同的结果。我不想尝试用一个问题回答两个问题,但也许我应该有。 – JamesRLamar 2013-03-08 20:11:56