openclassroom - linq query in c#




Comment convertir les résultats linq en HashSet ou HashedSet (7)

J'ai une propriété sur une classe qui est un ISet. J'essaie d'obtenir les résultats d'une requête linq dans cette propriété, mais je n'arrive pas à comprendre comment faire.

Fondamentalement, à la recherche de la dernière partie de ceci:

ISet<T> foo = new HashedSet<T>();
foo = (from x in bar.Items select x).SOMETHING;

Pourrait aussi faire ceci:

HashSet<T> foo = new HashSet<T>();
foo = (from x in bar.Items select x).SOMETHING;

Edit: C'est ce que j'ai fini par faire:

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
{
    return new HashSet<T>(source);
}

public static HashedSet<T> ToHashedSet<T>(this IEnumerable<T> source)
{
    return new HashedSet<T>(source.ToHashSet());
}

C'est assez simple :)

var foo = new HashSet<T>(from x in bar.Items select x);

et oui T est le type spécifié par OP :)



Il existe une méthode d'extension construite dans le framework .NET et dans le noyau .NET pour convertir un IEnumerable en HashSet : https://docs.microsoft.com/en-us/dotnet/api/?term=ToHashSet

public static System.Collections.Generic.HashSet<TSource> ToHashSet<TSource> (this System.Collections.Generic.IEnumerable<TSource> source);

Il semble que je ne puisse pas encore l'utiliser dans les bibliothèques standard .NET (au moment de l'écriture). Alors j'utilise cette méthode d'extension:

    [Obsolete("In the .NET framework and in NET core this method is available, " +
              "however can't use it in .NET standard yet. When it's added, please remove this method")]
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer = null) => new HashSet<T>(source, comparer);

Je ne pense pas qu'il y ait quoi que ce soit dans ce qui est fait ... mais il est vraiment facile d'écrire une méthode d'extension:

public static class Extensions
{
    public static HashSet<T> ToHashSet<T>(
        this IEnumerable<T> source,
        IEqualityComparer<T> comparer = null)
    {
        return new HashSet<T>(source, comparer);
    }
}

Notez que vous voulez vraiment une méthode d'extension (ou au moins une méthode générique d'une certaine forme) ici, parce que vous ne pouvez pas être capable d'exprimer le type de T explicitement:

var query = from i in Enumerable.Range(0, 10)
            select new { i, j = i + 1 };
var resultSet = query.ToHashSet();

Vous ne pouvez pas faire cela avec un appel explicite au constructeur HashSet<T> . Nous comptons sur l'inférence de type pour les méthodes génériques pour le faire pour nous.

Maintenant vous pouvez choisir de le nommer ToSet et retourner ISet<T> - mais je m'en tiens à ToHashSet et au type concret. Ceci est cohérent avec les opérateurs LINQ standard ( ToDictionary , ToList ) et permet une extension future (par exemple ToSortedSet ). Vous pouvez également vouloir fournir une surcharge spécifiant la comparaison à utiliser.


Passez simplement votre IEnumerable dans le constructeur de HashSet.

HashSet<T> foo = new HashSet<T>(from x in bar.Items select x);

Plutôt que la simple conversion de IEnumerable en HashSet, il est souvent pratique de convertir une propriété d'un autre objet en HashSet. Vous pourriez écrire ceci comme:

var set = myObject.Select(o => o.Name).ToHashSet();

mais, ma préférence serait d'utiliser des sélecteurs:

var set = myObject.ToHashSet(o => o.Name);

Ils font la même chose, et la seconde est évidemment plus courte, mais je trouve que l'idiome s'adapte mieux à mon cerveau (je pense que c'est comme ToDictionary).

Voici la méthode d'extension à utiliser, avec un soutien pour les comparateurs personnalisés en bonus.

public static HashSet<TKey> ToHashSet<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> selector,
    IEqualityComparer<TKey> comparer = null)
{
    return new HashSet<TKey>(source.Select(selector), comparer);
}

Vous pouvez simplement utiliser le constructeur IEnumerable HashSet.

HashSet<T> foo = new HashSet<T>((from x in bar.Items select x).ToArray());




linq