Estratto un IEqualityComparer implementazione o ignorare l'operatore di confronto predefinito da utilizzare metodo distinto

StackOverflow https://stackoverflow.com/questions/4250381

Domanda

Sto cercando di trovare un List<Author> distinta dato un List<BlogPost> in cui ogni BlogPost ha una proprietà Author. Ho trovato il metodo di estensione Distinct() in farmaci generici e sto cercando di usarla. In primo luogo, vorrei spiegare il mio ciclo e dove voglio usarlo, poi vi spiego le mie classi e dove sto avendo problemi.

Cercando di utilizzare distinte qui

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

In base a quello che ho leggere su MSDN , Distinct() sia utilizza l'operatore di confronto di default o un passato di operatore di confronto. Speravo (I obviosuly Non so se questo è fattibile) di scrivere un operatore di confronto in un punto ed essere in grado di usarlo per tutti i miei corsi in quanto tutti confronta con la stessa identica operazione uguaglianza (che confronta la proprietà GUID di ogni classe).

Tutte le mie classi ereditano dalla classe BasePage:

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

public class Author : BasePage

public class BlogPost : BasePage

Il mio è uguale metodo implementato nel BasePage la struttura paragonabile GUID che è unico per ciascuna. Quando chiamo Distinct() su un Author non sembra al lavoro. C'è un modo per concludere la di confronto in un posto e sempre in grado di usarlo, piuttosto che dover scrivere qualcosa come class AuhorComparer : IEqualityComparer<Auhor> dato che avevo allora bisogno di scrivere la stessa cosa per ogni classe, ogni volta che voglio usare Distinct() . o posso ignorare l'operatore di confronto di default in qualche modo non devo passare nulla al Distinct()?

È stato utile?

Soluzione

L'operazione Distinct non è probabilmente la soluzione migliore qui perché si finisce per costruire una potenzialmente molto grande elenco con i duplicati per poi subito ridursi ad elementi distinti. Probabilmente è meglio iniziare con un semplice HashSet<Author> per evitare di costruire la lista di grandi dimensioni.

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

Se si desidera utilizzare Distinct poi la strada migliore è quello di implementare IEquatable sul tipo Author. Quando non è dato un IEqualityComparer esplicita i metodi Distinct e altri LINQ alla fine di default nel usando l'implementazione IEquatable del tipo. Di solito attraverso EqualityComprare<T>.Default

Altri suggerimenti

Equals Override dovrebbe funzionare per voi. Una cosa che potrebbe andare male è che GetHashCode non viene sostituito al fianco di Eguali, che le linee guida quadro dettano dovrebbe accadere.

Il codice mostra solo l'idea principale, che, mi auguro, possa essere utile.

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; }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top