LINQ选择与匿名类型不同

GWL*_*osa 147 c# linq equality anonymous-types distinct

所以我有一组对象.确切的类型并不重要.从中我想提取一对特定属性的所有唯一对,因此:

myObjectCollection.Select(item=>new
                                {
                                     Alpha = item.propOne,
                                     Bravo = item.propTwo
                                }
                 ).Distinct();
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:在这种情况下会不会使用默认对象equals(这对我来说没用,因为每个对象都是新的)或者可以告诉它做一个不同的equals(在这种情况下,Alpha和Bravo的值相等) =>相等的实例)?有没有办法实现这个结果,如果不这样做的话?

Mat*_*ton 181

请阅读K. Scott Allen的精彩帖子:

所有人的平等......匿名类型

简短的回答(我引用):

事实证明,C#编译器会覆盖匿名类型的Equals和GetHashCode.两个重写方法的实现使用类型上的所有公共属性来计算对象的哈希代码并测试相等性.如果两个具有相同匿名类型的对象的属性具有相同的值 - 则对象相等.

因此,对返回匿名类型的查询使用Distinct()方法是完全安全的.

  • 它最终意味着两个匿名类型的相等性取决于成员的相等性,这对我来说很好,因为成员被定义在某个我可以得到的地方并且如果必须的话则覆盖相等.我只是不想为此创建一个只是为了覆盖equals. (4认同)
  • 可能值得请求MS将"密钥"语法引入到VB所具有的C#中(您可以将匿名类型的某些属性指定为"主键" - 请参阅我链接到的博客文章). (3认同)
  • 我认为,只有属性本身是值类型或实现值相等时,这才是正确的-请参阅我的答案。 (2认同)

小智 14

public class DelegateComparer<T> : IEqualityComparer<T>
{
    private Func<T, T, bool> _equals;
    private Func<T, int> _hashCode;
    public DelegateComparer(Func<T, T, bool> equals, Func<T, int> hashCode)
    {
        _equals= equals;
        _hashCode = hashCode;
    }
    public bool Equals(T x, T y)
    {
        return _equals(x, y);
    }

    public int GetHashCode(T obj)
    {
        if(_hashCode!=null)
            return _hashCode(obj);
        return obj.GetHashCode();
    }       
}

public static class Extensions
{
    public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, 
        Func<T, T, bool> equals, Func<T,int> hashCode)
    {
        return items.Distinct(new DelegateComparer<T>(equals, hashCode));    
    }
    public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items,
        Func<T, T, bool> equals)
    {
        return items.Distinct(new DelegateComparer<T>(equals,null));
    }
}

var uniqueItems=students.Select(s=> new {FirstName=s.FirstName, LastName=s.LastName})
            .Distinct((a,b) => a.FirstName==b.FirstName, c => c.FirstName.GetHashCode()).ToList();
Run Code Online (Sandbox Code Playgroud)

对不起早先搞砸了格式化


Geo*_*ker 5

有趣的是它在C#中有效,但在VB中无效

返回26个字母:

var MyBet = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ";
MyBet.ToCharArray()
.Select(x => new {lower = x.ToString().ToLower(), upper = x.ToString().ToUpper()})
.Distinct()
.Dump();
Run Code Online (Sandbox Code Playgroud)

返回52 ...

Dim MyBet = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
MyBet.ToCharArray() _
.Select(Function(x) New With {.lower = x.ToString.ToLower(), .upper = x.ToString.ToUpper()}) _
.Distinct() _
.Dump()
Run Code Online (Sandbox Code Playgroud)

  • 如果将`Key`关键字添加到匿名类型,`.Distinct()`将按预期工作(例如`New With {Key .lower = x.ToString.ToLower(),Key .upper = x.ToString.ToUpper ()}`). (11认同)
  • 科里是对的.正确翻译C#代码`new {A = b}`是`New {Key .A = b}`.匿名VB类中的非键属性是可变的,这就是它们通过引用进行比较的原因.在C#中,匿名类的所有属性都是不可变的. (3认同)