Réponses:
Si vous pouvez utiliser LINQ, vous pouvez utiliser:
var e = enumerable.First();
Cela lèvera une exception si enumerable est vide: auquel cas vous pouvez utiliser:
var e = enumerable.FirstOrDefault();
FirstOrDefault()
retournera default(T)
si l'énumérable est vide, ce qui sera null
pour les types référence ou la «valeur zéro» par défaut pour les types valeur.
Si vous ne pouvez pas utiliser LINQ, votre approche est techniquement correcte et n'est pas différente de la création d'un énumérateur à l'aide des méthodes GetEnumerator
et MoveNext
pour récupérer le premier résultat (cet exemple suppose que énumérable est un IEnumerable<Elem>
):
Elem e = myDefault;
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) {
if (enumer.MoveNext()) e = enumer.Current;
}
Joel Coehoorn mentionné .Single()
dans les commentaires; cela fonctionnera également, si vous vous attendez à ce que votre énumérable contienne exactement un élément - cependant, il lèvera une exception s'il est vide ou plus grand qu'un élément. Il existe une SingleOrDefault()
méthode correspondante qui couvre ce scénario de la même manière que FirstOrDefault()
. Cependant, David B explique que cela SingleOrDefault()
peut toujours lever une exception dans le cas où l'énumérable contient plusieurs éléments.
Edit: Merci Marc Gravell d' avoir souligné que je dois me débarrasser de mon IEnumerator
objet après l'avoir utilisé - j'ai édité l'exemple non LINQ pour afficher le using
mot - clé pour implémenter ce modèle.
Juste au cas où vous utilisez .NET 2.0 et n'avez pas accès à LINQ:
static T First<T>(IEnumerable<T> items)
{
using(IEnumerator<T> iter = items.GetEnumerator())
{
iter.MoveNext();
return iter.Current;
}
}
Cela devrait faire ce que vous recherchez ... il utilise des génériques afin que vous puissiez obtenir le premier élément sur n'importe quel type IEnumerable.
Appelez ça comme ça:
List<string> items = new List<string>() { "A", "B", "C", "D", "E" };
string firstItem = First<string>(items);
Ou
int[] items = new int[] { 1, 2, 3, 4, 5 };
int firstItem = First<int>(items);
Vous pouvez le modifier assez facilement pour imiter la méthode d'extension IEnumerable.ElementAt () de .NET 3.5:
static T ElementAt<T>(IEnumerable<T> items, int index)
{
using(IEnumerator<T> iter = items.GetEnumerator())
{
for (int i = 0; i <= index; i++, iter.MoveNext()) ;
return iter.Current;
}
}
Appelant ça comme ça:
int[] items = { 1, 2, 3, 4, 5 };
int elemIdx = 3;
int item = ElementAt<int>(items, elemIdx);
Bien sûr , si vous n'avez accès à LINQ, alors il y a beaucoup de bonnes réponses déjà ... affiché
Eh bien, vous n'avez pas spécifié la version de .Net que vous utilisez.
En supposant que vous ayez 3.5, une autre méthode est la méthode ElementAt:
var e = enumerable.ElementAt(0);
Elem e = enumerable.FirstOrDefault();
//do something with e
Utilisez FirstOrDefault ou une boucle foreach comme déjà mentionné. Il faut éviter de récupérer manuellement un énumérateur et d'appeler Current. foreach supprimera votre énumérateur pour vous s'il implémente IDisposable. Lorsque vous appelez MoveNext et Current, vous devez le supprimer manuellement (si cela est possible).
Si votre IEnumerable ne l'expose pas <T>
et que Linq échoue, vous pouvez écrire une méthode à l'aide de la réflexion:
public static T GetEnumeratedItem<T>(Object items, int index) where T : class
{
T item = null;
if (items != null)
{
System.Reflection.MethodInfo mi = items.GetType()
.GetMethod("GetEnumerator");
if (mi != null)
{
object o = mi.Invoke(items, null);
if (o != null)
{
System.Reflection.MethodInfo mn = o.GetType()
.GetMethod("MoveNext");
if (mn != null)
{
object next = mn.Invoke(o, null);
while (next != null && next.ToString() == "True")
{
if (index < 1)
{
System.Reflection.PropertyInfo pi = o
.GetType().GetProperty("Current");
if (pi != null) item = pi
.GetValue(o, null) as T;
break;
}
index--;
}
}
}
}
}
return item;
}
vous pouvez également essayer la version plus générique qui vous donne le ième élément
enumerable.ElementAtOrDefault (i));
J'espère que ça aide