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 ne sais pas comment le 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 également faire ceci:
HashSet<T> foo = new HashSet<T>();
foo = (from x in bar.Items select x).SOMETHING;
HashedSet
partie. Il est juste déroutant depuisC#
etLINQ
n'a rien appeléHashedSet
.Réponses:
Je ne pense pas qu'il y ait quoi que ce soit intégré qui fasse cela ... mais il est vraiment facile d'écrire une méthode d'extension:
Notez que vous voulez vraiment une méthode d'extension (ou au moins une méthode générique d'une certaine forme) ici, car vous ne pourrez peut-être pas exprimer le type de
T
explicitement:Vous ne pouvez pas faire cela avec un appel explicite au
HashSet<T>
constructeur. 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 de revenirISet<T>
- mais je m'en tiendrai auToHashSet
type de béton. Ceci est cohérent avec les opérateurs LINQ standard (ToDictionary
,ToList
) et permet une expansion future (par exempleToSortedSet
). Vous pouvez également vouloir fournir une surcharge spécifiant la comparaison à utiliser.la source
GetHashCode
etEquals
? Sinon, ils ne seront pas très bons dans un HashSet ...ForEach
, maisToHashSet
est beaucoup plus logique - je ne connais aucune raison de ne pas faireToHashSet
autre que la normale "ne répond pas à la barre d'utilité" (ce avec quoi je ne suis pas d'accord, mais ...)Passez simplement votre IEnumerable dans le constructeur de HashSet.
la source
bar.Items
va l'êtreT
. Étant donné la facilité avec laquelle cet objectif est général et la fréquence à laquelle les types anonymes apparaissent dans LINQ, je pense que cela vaut la peine de faire un pas supplémentaire.Cette fonctionnalité a été ajoutée en tant que méthode d'extension
IEnumerable<TSource>
à .NET Framework 4.7.2 :ToHashSet<TSource>(IEnumerable<TSource>)
ToHashSet<TSource>(IEnumerable<TSource>, IEqualityComparer<TSource>)
la source
Comme l'a déclaré @Joel, vous pouvez simplement passer votre énumérable. Si vous voulez faire une méthode d'extension, vous pouvez faire:
la source
Si vous avez juste besoin d'accéder en lecture seule à l'ensemble et que la source est un paramètre de votre méthode, alors j'irais avec
La raison en est que les utilisateurs peuvent déjà appeler votre méthode avec le
ISet
afin que vous n'ayez pas besoin de créer la copie.la source
Il existe une méthode d'extension construite dans le framework .NET et dans le noyau .NET pour convertir un
IEnumerable
enHashSet
: https://docs.microsoft.com/en-us/dotnet/api/?term=ToHashSetIl semble que je ne puisse pas encore l'utiliser dans les bibliothèques standard .NET (au moment de la rédaction). Alors j'utilise cette méthode d'extension:
la source
C'est assez simple :)
et oui T est le type spécifié par OP :)
la source
La réponse de Jon est parfaite. La seule mise en garde est que, en utilisant HashedSet de NHibernate, j'ai besoin de convertir les résultats en une collection. Existe-t-il un moyen optimal de procéder?
ou
Ou est-ce que je manque autre chose?
Edit: C'est ce que j'ai fini par faire:
la source
ToList
est généralement plus efficace queToArray
. Faut-il simplement l'implémenterICollection<T>
?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 pouvez écrire ceci comme:
mais ma préférence serait d'utiliser des sélecteurs:
Ils font la même chose, et le second est évidemment plus court, mais je trouve que l'idiome correspond mieux à mon cerveau (je pense que c'est comme ToDictionary).
Voici la méthode d'extension à utiliser, avec prise en charge des comparateurs personnalisés en bonus.
la source