在List <[linq_custom_object]>()上实现.Distinct()的正确方法是什么?

LaR*_*ite 4 .net c# linq distinct

我有这个DNS_Log有四个属性的类.我已经创建了一个这些对象的列表,我试图过滤这些对象仅用于不同的事件.(当填充列表时,有很多重复)

这是填充的列表:

dnsLogs.Add( new DNS_Log { Destination = destination, 
                           Source_IP = sourceIp, 
                           Domain_Controller = domainController, 
                           DateTime = datetime });
Run Code Online (Sandbox Code Playgroud)

这是我试图过滤掉不同的那些:

dnsLogs = dnsLogs.Distinct().ToList();
Run Code Online (Sandbox Code Playgroud)

为什么这不起作用?我是否需要在不同的参数中使用一些linq表达式?我想将对象作为一个整体来比较它们的属性.有没有更简单的方法呢?

PS我已经玩了一个IEqualityComparer<DNS_Log>似乎工作正常的自定义,但我不知道如何在这种情况下实现它.

ang*_*son 5

你有几个选择:

  1. 在类型上实现IEquatable <T>DNS_Log
  2. 覆盖Equals和GetHashCode而不实现 IEquatable<T>
  3. 实现单独的IEqualityComparer <T>并将其传递给Distinct

注意!在下面的所有代码中,相等性检查假定==操作员知道如何处理每种类型.对于DateTime成员来说肯定是这样(假设它也是 DateTime类型),但我显然无法保证其他成员都能正常工作.如果Destination成员拥有==尚未定义运算符的类型,则可能是错误的.由于您尚未为此比较器实现发布自己的代码,因此无法知道此处的操作.

IEquatable<T>

public class DNS_Log : IEquatable<DNS_Log>
{

    public bool Equals(DNS_Log other)
    {
        if (other == null)
            return false;

        return (other.Destination == Destination
                && other.Source_IP == Source_IP
                && other.Domain_Controller == Domain_Controller
                && other.DateTime == DateTime);
    }

    public override int GetHashCode()
    {
        int hash = 23;
        hash = hash * 59 + (Destination == null ? 0 : Destination.GetHashCode());
        hash = hash * 59 + (Source_IP == null ? 0 : Source_IP.GetHashCode());
        hash = hash * 59 + (Domain_Controller == null ? 0 : Domain_Controller.GetHashCode());
        hash = hash * 59 + DateTime.GetHashCode();
        return hash;
    }
}
Run Code Online (Sandbox Code Playgroud)

在没有接口的情况下覆盖Equals和GetHashCode

public class DNS_Log
{

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        var other = obj as DNS_Log;
        if (other == null) return false;

        ... rest the same as above
Run Code Online (Sandbox Code Playgroud)

分离 IEqualityComparer<T>

最后,您可以在调用时提供IEqualityComparer <T>Distinct:

dnsLogs = dnsLogs.Distinct(new DNS_LogEqualityComparer()).ToList();

public class DNS_LogEqualityComparer : IEqualityComparer<DNS_Log>
{
    public int GetHashCode(DNS_Log obj)
    {
        int hash = 23;
        hash = hash * 59 + (obj.Destination == null ? 0 : obj.Destination.GetHashCode());
        hash = hash * 59 + (obj.Source_IP == null ? 0 : obj.Source_IP.GetHashCode());
        hash = hash * 59 + (obj.Domain_Controller == null ? 0 : obj.Domain_Controller.GetHashCode());
        hash = hash * 59 + obj.DateTime.GetHashCode();
        return hash;
    }

    public bool Equals(DNS_Log x, DNS_Log y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null) return false;

        return (x.Destination == y.Destination
            && x.Source_IP == y.Source_IP
            && .Domain_Controller == y.Domain_Controller
            && x.DateTime == y.DateTime);
    }
}
Run Code Online (Sandbox Code Playgroud)