Existe-t-il un moyen courant de passer un seul élément de type T
à une méthode qui attend un IEnumerable<T>
paramètre? Le langage est C #, framework version 2.0.
Actuellement, j'utilise une méthode d'assistance (c'est .Net 2.0, j'ai donc tout un tas de méthodes d'aide à la coulée / projection similaires à LINQ), mais cela semble juste idiot:
public static class IEnumerableExt
{
// usage: IEnumerableExt.FromSingleItem(someObject);
public static IEnumerable<T> FromSingleItem<T>(T item)
{
yield return item;
}
}
Une autre façon serait bien sûr de créer et de remplir un List<T>
ou un Array
et de le passer à la place de IEnumerable<T>
.
[Modifier] En tant que méthode d'extension, elle pourrait être nommée:
public static class IEnumerableExt
{
// usage: someObject.SingleItemAsEnumerable();
public static IEnumerable<T> SingleItemAsEnumerable<T>(this T item)
{
yield return item;
}
}
Est-ce que j'ai râté quelque chose?
[Edit2] Nous avons trouvé someObject.Yield()
(comme @Peter l'a suggéré dans les commentaires ci-dessous) comme étant le meilleur nom pour cette méthode d'extension, principalement pour la brièveté, alors voici avec le commentaire XML si quelqu'un veut l'attraper:
public static class IEnumerableExt
{
/// <summary>
/// Wraps this object instance into an IEnumerable<T>
/// consisting of a single item.
/// </summary>
/// <typeparam name="T"> Type of the object. </typeparam>
/// <param name="item"> The instance that will be wrapped. </param>
/// <returns> An IEnumerable<T> consisting of a single item. </returns>
public static IEnumerable<T> Yield<T>(this T item)
{
yield return item;
}
}
la source
if (item == null) yield break;
Maintenant, vous êtes empêché de passer null ainsi que de profiter du modèle d'objet null (trivial) pourIEnumerable
. (foreach (var x in xs)
gère un videxs
très bien). Soit dit en passant, cette fonction est l'unité monadique pour la monade de liste qui estIEnumerable<T>
, et étant donné le festival d'amour de la monade chez Microsoft, je suis surpris que quelque chose comme ça ne soit pas dans le cadre en premier lieu.AsEnumerable
car une extension intégrée portant ce nom existe déjà . (QuandT
implémenteIEnumerable
, par exemplestring
.)Yield
? Rien ne vaut la brièveté.left==null
chèque ici. Cela brise la beauté du code et empêche le code d'être plus flexible - et si un jour vous deviez générer un singleton avec quelque chose qui peut être nul? Je veux dire, cenew T[] { null }
n'est pas la même chosenew T[] {}
, et un jour vous devrez peut-être les distinguer.Réponses:
Votre méthode d'aide est la façon la plus propre de le faire, OMI. Si vous passez une liste ou un tableau, un morceau de code sans scrupules pourrait le transtyper et modifier le contenu, ce qui entraînerait un comportement étrange dans certaines situations. Vous pouvez utiliser une collection en lecture seule, mais cela impliquera probablement encore plus d'habillage. Je pense que votre solution est aussi nette que possible.
la source
myDict.Keys.AsEnumerable()
oùmyDict
était de typeDictionary<CheckBox, Tuple<int, int>>
. Après avoir renommé la méthode d'extension enSingleItemAsEnumerable
, tout a commencé à fonctionner. Impossible de convertir IEnumerable <Dictionary <CheckBox, System.Tuple <int, int >>. KeyCollection> 'en' IEnumerable <CheckBox> '. Il existe une conversion explicite (il vous manque un casting?) Je peux vivre avec un hack pendant un certain temps, mais d'autres hackers puissants peuvent-ils trouver un meilleur moyen?dictionary.Values
commencer. Fondamentalement, ce qui se passe n'est pas clair, mais je vous suggère de commencer une nouvelle question à ce sujet.Eh bien, si la méthode attend un,
IEnumerable
vous devez passer quelque chose qui est une liste, même si elle ne contient qu'un seul élément.qui passe
comme l'argument devrait suffire je pense
la source
En C # 3.0, vous pouvez utiliser la classe System.Linq.Enumerable:
Cela va créer un nouvel IEnumerable qui ne contient que votre article.
la source
new[]{ item }
me sers de moi-même, je pensais que c'était une solution intéressante.En C # 3 (je sais que vous avez dit 2), vous pouvez écrire une méthode d'extension générique qui pourrait rendre la syntaxe un peu plus acceptable:
le code client est alors
item.ToEnumerable()
.la source
ToEnumerable
éviter de gâcherSystem.Linq.Enumerable.AsEnumerable
ToEnumerable
méthode d'extension pourIObservable<T>
, donc ce nom de méthode interfère également avec les conventions existantes. Honnêtement, je suggère de ne pas utiliser du tout une méthode d'extension, simplement parce qu'elle est trop générique.Cette méthode d'assistance fonctionne pour un élément ou plusieurs.
la source
params
pour construire le tableau, donc le code résultant est propre. Je n'ai pas décidé si je l'aime plus ou moins quenew T[]{ item1, item2, item3 };
pour plusieurs articles.Je suis un peu surpris que personne n'ait suggéré une nouvelle surcharge de la méthode avec un argument de type T pour simplifier l'API client.
Maintenant, votre code client peut simplement faire ceci:
ou avec une liste:
la source
DoSomething<T>(params T[] items)
ce qui signifie que le compilateur gérerait la conversion d'un seul élément en un tableau. (Cela vous permettrait également de passer plusieurs éléments séparés et, encore une fois, le compilateur se chargerait de les convertir en un tableau pour vous.)Soit (comme cela a été dit précédemment)
ou
En remarque, la dernière version peut aussi être sympa si vous voulez une liste vide d'un objet anonyme, par exemple
la source
Comme je viens de le découvrir et de voir que l'utilisateur LukeH l'a également suggéré, une belle façon simple de le faire est la suivante:
Ce modèle vous permettra d'appeler la même fonctionnalité de multiples façons: un seul élément; plusieurs éléments (séparés par des virgules); un tableau; une liste; une énumération, etc.
Je ne suis pas sûr à 100% de l'efficacité de l'utilisation de la méthode AsEnumerable, mais cela fonctionne vraiment.
Mise à jour: la fonction AsEnumerable semble assez efficace! ( référence )
la source
.AsEnumerable()
. ArrayYourType[]
implémente déjàIEnumerable<YourType>
. Mais ma question faisait référence au cas où seule la deuxième méthode (dans votre exemple) est disponible, et vous utilisez .NET 2.0, et vous souhaitez passer un seul élément.IEnumerable<T> MakeEnumerable<T>(params T[] items) {return items;}
méthode? On pourrait alors l'utiliser avec tout ce qui attendait unIEnumerable<T>
, pour n'importe quel nombre d'articles discrets. Le code doit être essentiellement aussi efficace que la définition d'une classe spéciale pour renvoyer un seul élément.Bien que ce soit exagéré pour une méthode, je pense que certaines personnes peuvent trouver les extensions interactives utiles.
Les extensions interactives (Ix) de Microsoft incluent la méthode suivante.
Qui peut être utilisé comme ceci:
Ix ajoute de nouvelles fonctionnalités que l'on ne trouve pas dans les méthodes d'extension Linq d'origine et est le résultat direct de la création des extensions réactives (Rx).
Pensez,
Linq Extension Methods
+Ix
=Rx
pourIEnumerable
.Vous pouvez trouver à la fois Rx et Ix sur CodePlex .
la source
Ceci est 30% plus rapide que
yield
ouEnumerable.Repeat
lorsqu'il est utilisé enforeach
raison de cette optimisation du compilateur C # , et des mêmes performances dans d'autres cas.dans ce test:
la source
new [] { i }
option est environ 3,2 fois plus rapide que votre option. De plus, votre option est environ 1,2 fois plus rapide que l'extension avecyield return
.SingleEnumerator GetEnumerator()
qui renvoie votre structure. Le compilateur C # utilisera cette méthode (il la recherche via la saisie de canard) au lieu de celles de l'interface et évite ainsi la boxe. De nombreuses collections intégrées utilisent cette astuce, comme List . Remarque: cela ne fonctionnera que si vous avez une référence directe àSingleSequence
, comme dans votre exemple. Si vous le stockez dans uneIEnumerable<>
variable, l'astuce ne fonctionnera pas (la méthode d'interface sera utilisée)IanG a un bon article sur le sujet , suggérant
EnumerableFrom()
comme nom (et mentionne que Haskell et Rx l'appellentReturn
).L'IIF de F # l'appelle aussi Return. F #Seq
appelle l'opérateursingleton<'T>
.Tentant si vous êtes prêt à être centré sur C # est de l'appeler
Yield
[faisant allusion à la personneyield return
impliquée dans sa réalisation].Si vous êtes intéressé par les aspects de la performance, James Michael Hare a également un article de retour zéro ou un article qui vaut bien une analyse.
la source
Ce n'est peut-être pas mieux mais c'est plutôt cool:
la source
Je suis d'accord avec les commentaires de @ EarthEngine sur le message d'origine, qui est que "AsSingleton" est un meilleur nom. Voir cette entrée wikipedia . Ensuite, il résulte de la définition de singleton que si une valeur nulle est passée comme argument, 'AsSingleton' devrait retourner un IEnumerable avec une seule valeur null au lieu d'un IEnumerable vide qui réglerait le
if (item == null) yield break;
débat. Je pense que la meilleure solution est d'avoir deux méthodes: 'AsSingleton' et 'AsSingletonOrEmpty'; où, dans le cas où un NULL est passé en argument, 'AsSingleton' renverra une seule valeur Null et 'AsSingletonOrEmpty' renverra un IEnumerable vide. Comme ça:Ensuite, celles-ci seraient plus ou moins analogues aux méthodes d'extension «First» et «FirstOrDefault» sur IEnumerable, ce qui semble juste.
la source
La façon la plus simple que je dirais serait
new T[]{item};
; il n'y a pas de syntaxe pour ce faire. L'équivalent le plus proche auquel je peux penser est leparams
mot - clé, mais bien sûr, cela vous oblige à avoir accès à la définition de la méthode et n'est utilisable qu'avec des tableaux.la source
Le code ci-dessus est utile lors de l'utilisation comme
Dans l'extrait de code ci-dessus, il n'y a pas de vérification vide / nulle et il est garanti qu'un seul objet est renvoyé sans avoir peur des exceptions. De plus, étant donné qu'il est paresseux, la fermeture ne sera pas exécutée tant qu'il n'aura pas été prouvé qu'aucune donnée existante ne correspond aux critères.
la source
MyData.Where(myCondition)
est vide, qui est déjà possible (et plus simple) avecDefaultIfEmpty()
:var existingOrNewObject = MyData.Where(myCondition).DefaultIfEmpty(defaultValue).First();
. Cela peut être encore simplifiévar existingOrNewObject = MyData.FirstOrDefault(myCondition);
si vous le souhaitezdefault(T)
et non une valeur personnalisée.Je suis un peu en retard à la fête mais je vais quand même partager mon chemin. Mon problème était que je voulais lier ItemSource ou WPF TreeView à un seul objet. La hiérarchie ressemble à ceci:
Projet> Parcelle (s)> Salle (s)
Il n'y aura toujours qu'un seul projet, mais je voulais toujours montrer le projet dans l'arborescence, sans avoir à passer une collection avec seulement un seul objet comme certains l'ont suggéré.
Comme vous ne pouvez transmettre que des objets IEnumerable en tant que ItemSource, j'ai décidé de rendre ma classe IEnumerable:
Et créez mon propre énumérateur en conséquence:
Ce n'est probablement pas la solution "la plus propre" mais cela a fonctionné pour moi.
EDIT
Pour maintenir le principe de responsabilité unique comme l'a souligné @Groo, j'ai créé une nouvelle classe wrapper:
Que j'ai utilisé comme ça
EDIT 2
J'ai corrigé une erreur de
MoveNext()
méthode.la source
SingleItemEnumerator<T>
classe a du sens, mais faire d'une classe un "élément unique enIEnumerable
soi" semble être une violation du principe de responsabilité unique. Peut-être que cela le rend plus pratique, mais je préférerais quand même l'envelopper au besoin.A classer sous "Pas forcément une bonne solution, mais quand même ... une solution" ou "Stupid LINQ tricks", vous pouvez combiner
Enumerable.Empty<>()
avecEnumerable.Append<>()
...... ou
Enumerable.Prepend<>()
...Les deux dernières méthodes sont disponibles depuis .NET Framework 4.7.1 et .NET Core 1.0.
Il s'agit d'une solution réalisable si l'on avait vraiment l' intention d'utiliser des méthodes existantes au lieu d'écrire les leurs, bien que je ne sois pas sûr que ce soit plus ou moins clair que la
Enumerable.Repeat<>()
solution . Il s'agit certainement d'un code plus long (en partie parce que l'inférence de paramètres de type n'est pas possibleEmpty<>()
) et crée cependant deux fois plus d'objets énumérateurs.Pour compléter ce "Saviez-vous que ces méthodes existent?" réponse,
Array.Empty<>()
pourrait être substituéEnumerable.Empty<>()
, mais il est difficile de prétendre que cela rend la situation ... meilleure.la source
J'ai récemment posé la même question sur un autre post ( Existe-t-il un moyen d'appeler une méthode C # nécessitant un IEnumerable <T> avec une seule valeur? ... avec benchmarking ).
Je voulais que les gens s'arrêtent ici pour voir la brève comparaison de référence montrée à ce poste plus récent pour 4 des approches présentées dans ces réponses.
Il semble que le simple fait d'écrire
new[] { x }
les arguments de la méthode soit la solution la plus courte et la plus rapide.la source