Question

Donc, j'ai regardé par environ 20 exemples sur ce sur DONC et d'ailleurs, mais je n'ai pas trouvé un qui couvre ce que je suis en train de faire.Ce - Puis-je définir mon type explicite comparateur inline? - ressemble à ce dont j'ai besoin, mais ne va pas assez loin (ou je ne comprends pas comment le prendre plus loin).

  • J'ai une Liste de LoadData, le LoadData objet a des champs de référence et de types de valeur
  • Besoin de regrouper sur un mélange de ref et de la valeur des champs, le projet de la sortie à un type anonyme
  • Besoin (je crois) pour fournir une coutume IEqualityComparer pour spécifier comment comparer l'égard du Groupe de champs, mais ils sont un type anonyme

    private class LoadData
    {
        public PeriodEndDto PeriodEnd { get; set; }
        public ComponentDto Component { get; set; }
        public string GroupCode { get; set; }
        public string PortfolioCode { get; set; }
    }
    

Le meilleur Groupe de la requête je dois aller si loin:

var distinctLoads = list.GroupBy(
    dl => new { PeriodEnd = dl.PeriodEnd, 
                Component = dl.Component, 
                GroupCode = dl.GroupCode },
    (key, data) => new {PeriodEnd = key.PeriodEnd, 
                Component = key.Component, 
                GroupCode = key.GroupCode, 
                PortfolioList = data.Select(d=>d.PortfolioCode)
                                    .Aggregate((g1, g2) => g1 + "," + g2)},
    null);

Ce groupe, mais il y a encore des doublons.

  1. Comment puis-je spécifier un code personnalisé pour comparer l'égard du Groupe de champs?Par exemple, les Composants pourraient être comparés par Composante.Code.
Était-ce utile?

La solution

Le problème ici est que votre type de clé est anonyme, ce qui signifie que vous ne pouvez pas déclarer une classe qui implémente IEqualityComparer<T> pour ce type de clé.Alors qu'il serait possible pour écrire un comparateur qui compare les types anonymes pour l'égalité d'une manière personnalisée (via une méthode générique, les délégués et l'inférence de type), il ne serait pas terriblement agréable.

Les deux plus simple, les options sont sans doute:

  • Faire de l'anonyme de type "fonctionne" en substituant est Égal à/GetHashCode dans PeriodEndDto et ComponentDto.Si il y a une égalité naturelle vous voulez les utiliser partout, c'est probablement la sanest option.Je recommande la mise en œuvre de IEquatable<T> ainsi
  • Ne pas utiliser un type anonyme du groupement pour l'utilisation d'un type nommé, et ensuite vous pouvez soit remplacer GetHashCode et Equals sur ce modèle, ou vous pourriez écrire un personnalisé comparateur d'égalité dans les conditions normales.

EDIT: ProjectionEqualityComparer ne pas vraiment travailler.Il serait possible d'écrire quelque chose de semblable, mais une sorte de CompositeEqualityComparer qui vous a permis de créer un comparateur d'égalité de plusieurs "projection + de comparaison par paires.Il serait assez moche par rapport à l'anonymat, du type de bien.

Autres conseils

EDIT:

Comme Jon Skeet points à l'extérieur, cette solution semble la meilleure qu'elle ne l'est, si vous ne pensez pas trop dur à ce sujet, parce que j'ai oublié de mettre en œuvre GetHashCode.Avoir à mettre en œuvre GetHashCode rend cette approche, comme Jon dit, dans sa réponse, "pas très agréable." Apparemment, c'est aussi l'explication de la (soi-disant "inexplicable") absence de EqualityComparer<T>.Create() dans le cadre de.Je vais laisser la réponse de référence, des exemples de ce que ne pas le faire, peut être instructif.

RÉPONSE ORIGINALE À CETTE QUESTION:

Vous pouvez utiliser la démarche proposée par le Comparer<T>.Create modèle présenté en .NET 4.5 (mais inexplicablement absent dans EqualityComparer<T>).Pour ce faire, créer un DelegateEqualityComparer<T> classe:

class DelegateEqualityComparer<T> : EqualityComparer<T>
{
    private readonly Func<T, T, bool> _equalityComparison;

    private DelegateEqualityComparer(Func<T, T, bool> equalityComparison)
    {
        if (equalityComparison == null)
            throw new ArgumentNullException("equalityComparison");
        _equalityComparison = equalityComparison;
    }

    public override bool Equals(T x, T y)
    {
        return _equalityComparison(x, y);
    }

    public static DelegateEqualityComparer<T> Create(
        Func<T, T, bool> equalityComparison)
    {
        return new DelegateEqualityComparer<T>(equalityComparison);
    }
}

Ensuite, écrivez les wrappers autour de la GroupBy méthodes d'accepter un Func<TKey, TKey, bool> délégué à la place de la IEqualityComparer<TKey> le paramètre.Ces méthodes envelopper le délégué dans un DelegateEqualityComparer<T> exemple, et de le transmettre à la correspondante GroupBy méthode.Exemple:

public static class EnumerableExt
{
    public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector,
        Func<TKey, TKey, bool> equalityComparison)
    {
        return source.GroupBy(
            keySelector,
            DelegateEqualityComparer<TKey>.Create(equalityComparison);
    }
}

Enfin, à votre site d'appel, vous pouvez utiliser quelque chose comme cette expression pour l' equalityComparison argument:

(a, b) => a.PeriodEnd.Equals(b.PeriodEnd)
    && a.Component.Code.Equals(b.Component.Code)
    && a.GroupCode.Equals(b.GroupCode)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top