2010-11-22 8 views
0

Я пытаюсь найти отличный List<Author> дал List<BlogPost> где каждый BlogPost имеет Author свойство. Я нашел метод расширения Distinct() в дженериках, и я пытаюсь его использовать. Во-первых, позвольте мне объяснить мой цикл и где я хочу его использовать, тогда я объясню свои занятия и где у меня проблемы.Аннотация реализация IEqualityComparer или переопределить компаратор по умолчанию использовать Distinct метод

Попытки использовать отчетливыми здесь

public List<Author> GetAuthors() { 

    List<BlogPost> posts = GetBlogPosts(); 
    var authors = new List<Author>(); 

    foreach (var bp in posts) { 
    authors.Add(bp.Author); 
    } 

    return authors.Distinct().ToList(); 
} 

Исходя из того, что я read on MSDN, Distinct() либо использует компаратор по умолчанию или сдавшим в компараторе. Я надеялся (я obviosuly не знаю, если это выполнимо), чтобы написать компаратор в одном месте и иметь возможность использовать его для всех моих классов, поскольку все они сравниваются по той же операции равенства (которая сравнивает свойство GUID каждый класс).

Все мои классы наследуют от класса BasePage:

public class BasePage : System.Web.UI.Page, IBaseTemplate, IEquatable<IBaseTemplate>, IEqualityComparer<IBaseTemplate> 

public class Author : BasePage 

public class BlogPost : BasePage 

Мой равно метод, реализованный в BasePage сравнивает GUID свойство, которое является уникальным для каждого. Когда я звоню Distinct() на Author, он не работает. Есть ли способ, которым я могу обернуть сопоставитель в одном месте и всегда иметь возможность использовать его, а не писать что-то вроде class AuhorComparer : IEqualityComparer<Auhor>, так как тогда мне нужно было написать одно и то же для каждого класса, каждый раз, когда я хочу использовать Distinct() , Или Могу ли я переопределить сопоставления по умолчанию, так что мне не нужно ничего пропускать до Distinct()?

ответ

2

Операция Distinct, вероятно, не лучшее решение здесь, потому что вы в конечном итоге создаете потенциально очень большой список с дубликатами, чтобы сразу же сжать его на отдельные элементы. Вероятно, лучше начать с HashSet<Author>, чтобы избежать создания большого списка.

public List<Author> GetAuthors() { 
    HashSet<Author> authorSet = new HashSet<Author>(); 
    foreach (var author in GetBlogPosts().Select(x => x.Author)) { 
    authorSet.Add(author); 
    } 
    return authorSet.ToList(); 
} 

Если вы хотите использовать Distinct то лучший маршрут для реализации IEquatable на Author типа. Если не указано явное значение IEqualityComparer, то Distinct и другие методы LINQ в конечном итоге по умолчанию будут использовать реализацию типа IEquatable. Обычно через EqualityComprare<T>.Default

+0

Спасибо за предложение HashSet. Я внедрил ваши изменения, но я все равно получаю список того же размера. У меня есть список 3 сообщений, у двух есть один и тот же автор, у одного есть совершенно другой автор. Тем не менее, я получаю список из 3 авторов. – 2010-11-22 21:42:17

0

Override Equals должен работать на вас. Одна вещь, которая может пойти не так, заключается в том, что GetHashCode не переопределяется вместе с Equals, который должен соответствовать диктовке рамок.

0

Код показывает только основную идею, которая, я надеюсь, будет полезна.

public class Repository 
{ 
    public List<Author> GetAuthors() 
    { 
     var authors = new List<Author> 
         { 
          new Author{Name = "Author 1"}, 
          new Author{Name = "Author 2"}, 
          new Author{Name = "Author 1"} 
         }; 
     return authors.Distinct(new CustomComparer<Author>()).ToList(); 
    } 

    public List<BlogPost> GetBlogPosts() 
    { 
     var blogPosts = new List<BlogPost> 
     { 
      new BlogPost {Text = "Text 1"}, 
      new BlogPost {Text = "Text 2"}, 
      new BlogPost {Text = "Text 1"} 
     }; 
     return blogPosts.Distinct(new CustomComparer<BlogPost>()).ToList(); 
    } 
} 

//This comparer is required only one. 
public class CustomComparer<T> : IEqualityComparer<T> where T : class 
{ 
    public bool Equals(T x, T y) 
    { 
     if (y == null && x == null) 
     { 
      return true; 
     } 
     if (y == null || x == null) 
     { 
      return false; 
     } 
     if (x is Author && y is Author) 
     { 
      return ((Author)(object)x).Name == ((Author)(object)y).Name; 
     } 
     if (x is BlogPost && y is BlogPost) 
     { 
      return ((BlogPost)(object)x).Text == ((BlogPost)(object)y).Text; 
     } 
     //for next class add comparing logic here 
     return false; 
    } 

    public int GetHashCode(T obj) 
    { 
     return 0; // actual generating hash code should be here 
    } 
} 

public class Author 
{ 
    public string Name { get; set; } 
} 

public class BlogPost 
{ 
    public string Text { get; set; } 
}