문제

class Program
{
    static void Main(string[] args)
    {
        List<Book> books = new List<Book> 
        {
            new Book
            {
                Name="C# in Depth",
                Authors = new List<Author>
                {
                    new Author 
                    {
                        FirstName = "Jon", LastName="Skeet"
                    },
                     new Author 
                    {
                        FirstName = "Jon", LastName="Skeet"
                    },                       
                }
            },
            new Book
            {
                Name="LINQ in Action",
                Authors = new List<Author>
                {
                    new Author 
                    {
                        FirstName = "Fabrice", LastName="Marguerie"
                    },
                     new Author 
                    {
                        FirstName = "Steve", LastName="Eichert"
                    },
                     new Author 
                    {
                        FirstName = "Jim", LastName="Wooley"
                    },
                }
            },
        };


        var temp = books.SelectMany(book => book.Authors).Distinct();
        foreach (var author in temp)
        {
            Console.WriteLine(author.FirstName + " " + author.LastName);
        }

        Console.Read();
    }

}
public class Book
{
    public string Name { get; set; }
    public List<Author> Authors { get; set; }
}
public class Author
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public override bool Equals(object obj)
    {
        return true;
        //if (obj.GetType() != typeof(Author)) return false;
        //else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName;
    }

}

이것은 "LINQ in Action"의 예를 기반으로합니다. 리스팅 4.16.

이것은 Jon Skeet을 두 번 인쇄합니다. 왜요? 저자 클래스에서 Equals 메소드를 재정의하려고 시도했습니다. 여전히 뚜렷한 것은 작동하지 않는 것 같습니다. 내가 무엇을 놓치고 있습니까?

편집 : == 및! = 운영자 오버로드를 추가했습니다. 여전히 도움이 없습니다.

 public static bool operator ==(Author a, Author b)
    {
        return true;
    }
    public static bool operator !=(Author a, Author b)
    {
        return false;
    }
도움이 되었습니까?

해결책

LINQ Clost는 사용자 정의 객체와 관련하여 그다지 똑똑하지 않습니다.

그것이하는 것은 당신의 목록을보고 그것이 두 개의 다른 객체를 가지고 있음을 보는 것입니다 (회원 필드에 대해 동일한 값을 가지고 있다는 것은 신경 쓰지 않습니다).

하나의 해결 방법은 표시된대로 iquationable 인터페이스를 구현하는 것입니다. 여기.

저자 클래스를 수정하면 작동해야합니다.

public class Author : IEquatable<Author>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public bool Equals(Author other)
    {
        if (FirstName == other.FirstName && LastName == other.LastName)
            return true;

        return false;
    }

    public override int GetHashCode()
    {
        int hashFirstName = FirstName == null ? 0 : FirstName.GetHashCode();
        int hashLastName = LastName == null ? 0 : LastName.GetHashCode();

        return hashFirstName ^ hashLastName;
    }
}

dotnetfiddle로 시도하십시오

다른 팁

그만큼 Distinct() 방법 검사 참조 유형에 대한 참조 평등. 이것은 동일한 값을 포함하는 다른 객체가 아닌 문자 그대로 동일한 객체를 복제 한 것을 찾고 있음을 의미합니다.

있습니다 초과 적재 필요한 iqualitycomparer, 따라서 주어진 객체가 다른 객체인지 여부를 결정하기 위해 다른 논리를 지정할 수 있습니다.

저자가 일반적으로 일반적인 물체처럼 행동하기를 원한다면 (즉, 평등 만 참조) 이름 값에 따른 뚜렷한 점검 평등의 목적으로 iqualitycomparer. 이름 값을 기준으로 저자 객체를 비교하려면 항상 gethashcode 및 동등한 것을 무시하십시오, 또는 iquatable을 구현하십시오.

두 명의 회원 IEqualityComparer 인터페이스입니다 Equals 그리고 GetHashCode. 두 가지지 여부를 결정하기위한 논리 Author 첫 번째 이름과 성 문자열이 동일하다면 객체는 동일합니다.

public class AuthorEquals : IEqualityComparer<Author>
{
    public bool Equals(Author left, Author right)
    {
        if((object)left == null && (object)right == null)
        {
            return true;
        }
        if((object)left == null || (object)right == null)
        {
            return false;
        }
        return left.FirstName == right.FirstName && left.LastName == right.LastName;
    }

    public int GetHashCode(Author author)
    {
        return (author.FirstName + author.LastName).GetHashCode();
    }
}

구현하지 않고 다른 솔루션 IEquatable, Equals 그리고 GetHashCode LINQ를 사용하는 것입니다 GroupBy 방법 및 IGROUPING에서 첫 번째 항목을 선택합니다.

var temp = books.SelectMany(book => book.Authors)
                .GroupBy (y => y.FirstName + y.LastName )
                .Select (y => y.First ());

foreach (var author in temp){
  Console.WriteLine(author.FirstName + " " + author.LastName);
}

사용자 정의 된 데이터 유형 목록에서 뚜렷한 값을 얻는 또 하나의 방법이 있습니다.

YourList.GroupBy(i => i.Id).Select(i => i.FirstOrDefault()).ToList();

확실히, 그것은 뚜렷한 데이터 세트를 제공 할 것입니다

Distinct() 열거 가능한 객체에 대한 기본 평등 비교를 수행합니다. 당신이 무시하지 않은 경우 Equals() 그리고 GetHashCode(), 그런 다음 기본 구현을 사용합니다 object, 참조를 비교합니다.

간단한 해결책은 a를 추가하는 것입니다 옳은 구현 Equals() 그리고 GetHashCode() 비교하는 객체 그래프에 참여하는 모든 클래스에 (즉, 책과 저자).

그만큼 IEqualityComparer 인터페이스는 구현할 수있는 편의성입니다 Equals() 그리고 GetHashCode() 비교 해야하는 클래스의 내부에 액세스 할 수 없거나 다른 비교 방법을 사용하는 경우 별도의 클래스에서.

equals ()를 재정의하지만 gethashcode ()를 무시해야합니다.

위의 답변은 잘못되었습니다 !!! MSDN에 명시된 바와 같이 별개의 기본 적도를 반환합니다. 기본 속성은 Type T가 System.Iequatable 인터페이스를 구현하는지 여부를 확인하고 그렇다면 해당 구현을 사용하는 평등을 반환합니다. 그렇지 않으면 대상의 재정의를 사용하는 평등을 반환합니다.

그것은 당신이 오버 사이드가 괜찮다는 것을 의미합니다.

코드가 작동하지 않는 이유는 FirstName == LastName을 확인하기 때문입니다.

보다 https://msdn.microsoft.com/library/bb348436(v=vs.100).aspx 그리고 https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top