What is the correct way to implement .Distinct () in List <[linq_custom_object]> ()?

I have a class DNS_Logthat has four properties. I created a list of these objects that I am trying to filter, but only for individual occurrences. (When the list is populated, there are many repetitions)

Listing is populated here:

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

Here is my attempt to try to filter out only individual ones:

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

Why is this not working? Do I need some linq expression in a separate parameter? I want to compare objects in general by their properties. Is there an easier way to do this?

PS I played with creating a custom IEqualityComparer<DNS_Log>one that seems to work fine, but I don't know how to implement it in this scenario.

+4
3

:

  • IEqualityComparer<DNS_Log> Distinct (- dnsLogs.Distinct(myEqualityComparerInstance).ToList();
  • DNS_Log IEquatable<DNS_Log>
  • Equals GetHashCode DNS_Log
+2

:

! , == , . DateTime ( , DateTime), , , , . , == , , , . , , .

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;
    }
}

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

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);
    }
}
+5

?

, Distinct GetHashCode + Equals . , , .

, :

  • You can either implement custom IEqualityComparer<T>to overloadDistinct
  • or override Equals+ GetHashCodein your class
  • Another (less efficient) approach that does not need to create a new class or modify an existing one is to use the built-in GetHashCode+ Equalsanonymous type and Enumerable.GroupBy:

    IEnumerable<DNS_Log> distinctLogs = 
        from dns in dnsLogs
        group dns by  new { dns.Destination, dns.Source_IP,dns.Domain_Controller, dns.DateTime } into g 
        select g.First(); // change logic if you don't want an arbitrary object(first)
    

Here is an example of the second approach:

public class DNS_Log 
{
    public string Destination{ get; set; }
    public int Source_IP { get; set; }
    public string Domain_Controller { get; set; }
    public DateTime DateTime { get; set; }

    public override bool Equals(object obj)
    {
        DNS_Log c2 = obj as DNS_Log;
        if (obj == null) return false;
        return Destination == c2.Destination && Source_IP == c2.Source_IP
            && Domain_Controller == c2.Domain_Controller && DateTime == c2.DateTime;
    }

    public override int GetHashCode()
    {
        unchecked 
        {
            int hash = 17;
            hash = hash * 23 + Destination.GetHashCode();
            hash = hash * 23 + Source_IP;
            hash = hash * 23 + Domain_Controller.GetHashCode();
            hash = hash * 23 + DateTime.GetHashCode();
            return hash;
        }
    }
}

Equalsand GetHashCodeclass IEqualityComparer-class (1.) will be similar.

+1
source

Source: https://habr.com/ru/post/1531593/


All Articles