Аннотация Имея реализация IEQUITALICAMPER или переопределить сравнительный по умолчанию для использования различного метода
-
27-09-2019 - |
Вопрос
Я пытаюсь найти отчетливый List<Author>
дано а List<BlogPost>
где каждый BlogPost
имеет АН Author
имущество. Я нашел 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();
}
Основываясь на том, что я Читайте на MSDN, Distinct()
Либо использует компаратор по умолчанию или пропущенное в сравнении. Я надеялся (я читаю не знаю, если это сделано), чтобы написать сравнительную систему в одном месте и иметь возможность использовать его для всех моих классов, поскольку все они сравнивают то же самое равенство (что сравнивает 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()
?
Решение
То 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
Другие советы
Переопределенные равны должны работать для вас. Одна вещь, которая может быть неправильной, заключается в том, что GetHashCode не переопределяется рядом с равными, которые должны случиться рамочные руководящие принципы.
Кодекс показывает только основную идею, которую, я надеюсь, будет полезна.
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; }
}