Question

existe-t-il un moyen dans .NET (ou une sorte de méthode d'extension standard) de poser des questions sur une énumération?

Par exemple, l'élément actuel est-il le premier ou le dernier élément de l'énumération:

string s = "";

foreach (var person in PeopleListEnumerator) {

  if (PeopleListEnumerator.IsFirstItem) s += "[";

  s += person.ToString();

  if (!PeopleListEnumerator.IsLastItem) s += ",";
  else s += "]";
}
Était-ce utile?

La solution

Juste pour le plaisir, une solution au problème général ne nécessitant pas d’évaluation approfondie et comportant une seule variable locale (à l’exception de l’énumérateur):

static class TaggedEnumerableExtensions
{
    public class TaggedItem<T>
    {
        public TaggedItem(T value, bool isFirst, bool isLast)
        {
            IsFirst = isFirst;
            IsLast = isLast;
            Value = value;
        }
        public T Value { get; private set; }
        public bool IsFirst { get; private set; }
        public bool IsLast { get; private set; }
    }
    public static IEnumerable<TaggedItem<T>> ToTaggedEnumerable<T>(this IEnumerable<T> e)
    {
        using (var enumerator = e.GetEnumerator()) {
            if (!enumerator.MoveNext())
                yield break;
            var current = enumerator.Current;
            if (!enumerator.MoveNext()) {
                yield return new TaggedItem<T>(current, true, true);
                yield break;
            } else {
                yield return new TaggedItem<T>(current, true, false);
            }

            for (;;) {
                current = enumerator.Current;
                if (!enumerator.MoveNext()) {
                    yield return new TaggedItem<T>(current, false, true);
                    yield break;
                }
                yield return new TaggedItem<T>(current, false, false);
            }
        }
    }
}

Test:

class Program
{
    static void Main(string[] args)
    {
        foreach (var item in Enumerable.Range(0, 10).ToTaggedEnumerable()) {
            Console.WriteLine("{0} {1} {2}", item.IsFirst, item.IsLast, item.Value);
        }
    }
}

Autres conseils

Si votre collection est une liste, vous pouvez faire:

string s = "[" + String.Join(",", PeopleList.ToArray()) + "]";

Pas que je sache. Vous pouvez cependant essayer d'écrire vous-même de telles méthodes d'extension. Ou gardez une trace du premier / dernier élément ailleurs.

Eric Lippert avait un article de blog à propos de ce genre de problème récemment, avec quelques réflexions sur la façon de modifier la description de votre problème afin de refléter plus précisément ce que vous voulez réellement.

Vous ferez probablement mieux d'utiliser un String.Join . avec un peu de LINQ dans ce cas:

String.Join(
  ",",
  (from p in PeopleListEnumerator
  select p.ToString()).ToArray()
)

L'interface IEnumerable ne définit ni n'attend les éléments qu'elle renvoie dans un ordre donné. Donc, le concept de & Quot; premier & Quot; ne s'applique pas toujours.

Cependant, pour ce motif particulier, c’est ce que je fais

StringBuilder result = new StringBuilder();
result.Append( '[' );

foreach( var person in PeopleListEnumerator )
{
    if( result.Length > 1 )
        result.Append( ',' );
    result.Append( person.ToString() );
}

result.Append( ']' );

Jon Skeet a écrit Enumérations intelligentes . pour fournir ce type de fonctionnalité et ils font partie de la bibliothèque MiscUtils .

Cela dit, votre exemple spécifique est mieux résolu par l’approche String.Join (), comme beaucoup d’autres l’ont souligné. L'écriture d'une string Join(this IEnumerable<T>,string) extension générale n'est pas difficile et est donc utilisable dans d'autres situations sans avoir à recourir à des tableaux temporaires agaçants.

En utilisant LINQ, vous pouvez faire:

string s = 
    string.Format("[{0}]", string.Join(",",PeopleListEnumerator.Select(p => p.ToString()).ToArray()));

Je me trouve à définir et à utiliser une citation &; book first " variable locale, par exemple:

string s = "[";
bool first = true;

foreach (var person in PeopleListEnumerator) {

  if (first)
    first = false;
  else
    s += ",";
  s += person.ToString();
}
s += "]";

Ce code correspond étroitement à ce que vous voulez vraiment accomplir:

StringBuilder s = new StringBuilder("[");
string delimiter = "";

foreach (var person in PeopleListEnumerator) {  
  s.Append(delimiter).Append(person.ToString());
  delimiter = ",";
}

return s.Append("]").ToString();

La façon dont j'écorcherais ce chat (oui, il y a autant de façons) serait:

StringBuilder sb = new StringBuilder();

foreach (var person in PeopleListEnumerator )
{
    sb.AppendFormat(",{0}", person.ToString());
}

string s = "[" + sb.ToString().Substring(1) + "]";

J'espère que cela vous aidera ...

Dans .NET, les énumérations n’ont aucune notion d’ordre, sauf par valeur. Si vous voulez une première et dernière énumération, je vous suggérerais de définir explicitement ce que sont ces première et dernière valeurs. L'énumération suivante en est un exemple:

public enum PlayerType : byte
{
    Starter = byte.MinValue,
    RegularPlayer = 1,
    BenchWarmer = 2,
    Closer = byte.MaxValue
}

Vous pouvez ensuite exprimer quelque chose de similaire au suivant:

List<byte> values = new List<byte>((byte[])Enum.GetValues(typeof(PlayerType)));

PlayerType starter = (PlayerType)values.Min();
PlayerType closer = (PlayerType)values.Max();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top