是的,所以我有一个可枚举的,并希望从中获得不同的值.
使用System.Linq,当然有一个名为的扩展方法Distinct.在简单的情况下,它可以在没有参数的情况下使用,例如:
var distinctValues = myStringList.Distinct();
Run Code Online (Sandbox Code Playgroud)
好的,但如果我有一个可以指定相等性的可枚举对象,唯一可用的重载是:
var distinctValues = myCustomerList.Distinct(someEqualityComparer);
Run Code Online (Sandbox Code Playgroud)
equality comparer参数必须是.的实例IEqualityComparer<T>.当然,我可以做到这一点,但它有点冗长,而且很有说服力.
我所期望的是一个需要lambda的重载,比如Func <T,T,bool>:
var distinctValues
= myCustomerList.Distinct((c1, c2) => c1.CustomerId == c2.CustomerId);
Run Code Online (Sandbox Code Playgroud)
任何人都知道是否存在某些此类扩展或某些等效的解决方法?或者我错过了什么?
或者,有没有一种方法可以指定IEqualityComparer内联(embarass me)?
更新
我找到了Anders Hejlsberg对MSDN论坛中关于这个主题的帖子的回复.他说:
您将遇到的问题是,当两个对象比较相等时,它们必须具有相同的GetHashCode返回值(否则Distinct内部使用的哈希表将无法正常运行).我们使用IEqualityComparer,因为它将Equals和GetHashCode的兼容实现打包到一个接口中.
我认为那是有道理的..
我试图理解IEqualityComparer接口的GetHashCode方法的作用.
以下示例来自MSDN:
using System;
using System.Collections.Generic;
class Example {
static void Main() {
try {
BoxEqualityComparer boxEqC = new BoxEqualityComparer();
Dictionary<Box, String> boxes = new Dictionary<Box,
string>(boxEqC);
Box redBox = new Box(4, 3, 4);
Box blueBox = new Box(4, 3, 4);
boxes.Add(redBox, "red");
boxes.Add(blueBox, "blue");
Console.WriteLine(redBox.GetHashCode());
Console.WriteLine(blueBox.GetHashCode());
}
catch (ArgumentException argEx) {
Console.WriteLine(argEx.Message);
}
}
}
public class Box {
public Box(int h, int l, int w) {
this.Height = h;
this.Length = l;
this.Width = w;
}
public int …Run Code Online (Sandbox Code Playgroud) 可能重复:
不能将运算符==应用于C#中的泛型类型?
我编写了这样的代码:
public bool IsDataChanged()
{
T value1 = GetValue2;
T value2 = GetValue1();
return (valueInDB != valueFromView);
}
Run Code Online (Sandbox Code Playgroud)
现在该函数没有编译错误" 运算符'!='不能应用于'T'和'T'类型的操作数 ".我该怎么做才能使这个功能起作用?
我有从数据库派生的以下EF类(简化)
class Product
{
public string ProductId;
public string ProductName;
public string CategoryId;
public string CategoryName;
}
Run Code Online (Sandbox Code Playgroud)
ProductId是表的主键.
对于DB设计者做出的糟糕的设计决策(我无法修改它),我有CategoryId和CategoryName在这个表中.
我需要一个DropDownList的使用(不同)CategoryId的价值,并CategoryName为文本.因此我应用了以下代码:
product.Select(m => new {m.CategoryId, m.CategoryName}).Distinct();
Run Code Online (Sandbox Code Playgroud)
从逻辑上讲,它应该使用CategoryId和CategoryName作为属性创建一个匿名对象.在Distinct()保证有没有重复对(CategoryId,CategoryName).
但实际上它不起作用.据我所知,Distinct()当集合中只有一个字段时,它就会忽略它们......这是正确的吗?有没有解决方法?谢谢!
UPDATE
对不起product是:
List<Product> product = new List<Product>();
Run Code Online (Sandbox Code Playgroud)
我找到了另一种获得相同结果的方法Distinct():
product.GroupBy(d => new {d.CategoryId, d.CategoryName})
.Select(m => new {m.Key.CategoryId, m.Key.CategoryName})
Run Code Online (Sandbox Code Playgroud) 是否有使用的默认IEqualityComparer<T>实现ReferenceEquals?
EqualityComparer<T>.Default使用ObjectComparer,它使用object.Equals().在我的例子中,对象已经实现IEquatable<T>,我需要忽略并仅通过对象的引用进行比较.
我碰巧看到了一些代码,其中这个人将lambda表达式传递给ArrayList.Sort(这里是IComparer)或IEnumerable.SequenceEqual(IEnumerable列表,IEqualityComparer here),其中需要IComparer或IEqualityComparer.
我不能确定我是否看过它,或者我只是在做梦.我似乎无法在这些集合中找到任何接受Func <>或其方法签名中的委托的扩展.
有这样的过载/扩展方法吗?或者,如果没有,是否有可能像这样捣乱并传递一个算法(读委托),其中预期单方法接口?
更新 谢谢大家.那正是我所想.我一定是在做梦.我知道如何编写转换.我只是不确定我是否见过这样的东西,或者只是觉得我已经看过了.
又一次更新 看,在这里,我找到了一个这样的实例.毕竟我并没有做梦.看看这家伙在这做什么.是什么赋予了?
这是另一个更新:
好的,我明白了.那家伙正在使用Comparison<T>超载.尼斯.很好,但完全容易误导你.不过很好.谢谢.
linq ienumerable extension-methods icomparer iequalitycomparer
是否可以定义IComparer的匿名实现?
我相信Java允许内联定义匿名类 - C#?
看看这段代码我想定义一个自定义IComparer内联
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer
)
Run Code Online (Sandbox Code Playgroud) 我有这个
var n = ItemList.Select(s => new { s.Vchr, s.Id, s.Ctr, s.Vendor, s.Description, s.Invoice }).ToList();
n.AddRange(OtherList.Select(s => new { s.Vchr, s.Id, s.Ctr, s.Vendor, s.Description, s.Invoice }).ToList(););
Run Code Online (Sandbox Code Playgroud)
如果允许,我想这样做
n = n.Distinct((x, y) => x.Vchr == y.Vchr)).ToList();
Run Code Online (Sandbox Code Playgroud)
我尝试使用通用的LambdaComparer,但由于我使用的是匿名类型,因此没有类型与之关联.
"帮助我Obi Wan Kenobi,你是我唯一的希望"
BCL中有几个地方可以使用IEqualityComparer.像Enumerable.Contains或Dictionary Constructor.如果我对默认的不满意,我可以提供我的比较器.
有时我想知道集合是否包含我所引用的那个对象.不是任何其他意义上被认为"相等"的那个.
问题是:BCL中是否存在仅依赖于ReferenceEquals方法的标准相等比较器?
我自己写的是这样的:
class ReferenceComparer<T> : IEqualityComparer<T> where T : class
{
private static ReferenceComparer<T> m_instance;
public static ReferenceComparer<T> Instance
{
get
{
return m_instance ?? (m_instance = new ReferenceComparer<T>());
}
}
public bool Equals(T x, T y)
{
return ReferenceEquals(x, y);
}
public int GetHashCode(T obj)
{
return RuntimeHelpers.GetHashCode(obj);
}
}
Run Code Online (Sandbox Code Playgroud)
我没有测试它彻底,也没有考虑很多的场景,但它似乎使Enumerable.Contains和Dictionary很高兴.
我们编写了一个如下所示的测试.此测试要求我们Equal为CodeTableItem-class 创建了en -overload :
ICollection<CodeTableItem> expectedValutaList = new List<CodeTableItem>();
expectedValutaList.Add(new CodeTableItem("DKK", "DKK"));
expectedValutaList.Add(new CodeTableItem("EUR", "EUR"));
RepoDac target = new RepoDac();
var actual = target.GetValutaKd();
CollectionAssert.AreEqual(expectedValutaList.ToList(),actual.ToList());
Run Code Online (Sandbox Code Playgroud)
测试工作正常,但是对Equality函数有一个不幸的依赖,这意味着如果我CodeTableItem用一个字段扩展-class,并忘记扩展Equals-function,单元测试仍然会运行绿色,尽管我们不测试所有字段.我们希望避免这种Equality污染(参见测试特定平等),这种污染只是为了符合测试而编写的.
我们尝试过使用OfLikeness,并以这种方式重写了测试:
ICollection<CodeTableItem> expectedValutaList = new List<CodeTableItem>();
expectedValutaList.Add(new CodeTableItem("DKK", "DKK"));
expectedValutaList.Add(new CodeTableItem("EUR", "EUR"));
var expectedValutaListWithLikeness =
expectedValutaList.AsSource().OfLikeness<List<CodeTableItem>>();
RepoDac target = new RepoDac();
ICollection<CodeTableItem> actual;
actual = target.GetValutaKd();
expectedValutaListWithLikeness.ShouldEqual(actual.ToList());
Run Code Online (Sandbox Code Playgroud)
但测试失败是因为Capacity不相等.我编写了多次运行反射的代码,并且通常最终实现了忽略字段的重载.有没有办法用OfLikeness或忽略某些字段ShouldEqual?或者还有其他方法可以解决这个问题吗?
.net collections unit-testing autofixture semantic-comparison
c# ×7
.net ×4
linq ×3
lambda ×2
autofixture ×1
c#-3.0 ×1
collections ×1
comparison ×1
distinct ×1
generics ×1
gethashcode ×1
icomparer ×1
ienumerable ×1
unit-testing ×1