первое и последнее перечисление .net
-
20-08-2019 - |
Вопрос
есть ли способ в .NET (или какие-то стандартные методы расширения) задавать вопросы о перечислении?
Например, является ли текущий элемент первым или последним элементом в перечислении:
string s = "";
foreach (var person in PeopleListEnumerator) {
if (PeopleListEnumerator.IsFirstItem) s += "[";
s += person.ToString();
if (!PeopleListEnumerator.IsLastItem) s += ",";
else s += "]";
}
Решение
Просто ради удовольствия, решение общей проблемы, которое не требует тщательной оценки и имеет единственную локальную переменную (кроме перечислителя):
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);
}
}
}
}
Тест:
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);
}
}
}
Другие советы
Если ваша коллекция представляет собой Список, вы можете сделать:
string s = "[" + String.Join(",", PeopleList.ToArray()) + "]";
Насколько мне известно, нет.Однако вы можете попробовать написать такие методы расширения самостоятельно.Или следите за первым / последним элементом в другом месте.
У Эрика Липперта был запись в блоге о проблеме такого рода недавно вместе с некоторыми мыслями о том, как изменить описание вашей проблемы, чтобы более точно отразить то, чего вы на самом деле хотите.
Вероятно, вам лучше использовать Строка.Соединение с некоторым LINQ в этом случае:
String.Join(
",",
(from p in PeopleListEnumerator
select p.ToString()).ToArray()
)
Интерфейс IEnumerable не определяет и не ожидает, что возвращаемые им элементы будут находиться в каком-либо заданном порядке.Таким образом, понятие "Первый" не всегда применимо.
Однако для этого конкретного шаблона это то, что я делаю
StringBuilder result = new StringBuilder();
result.Append( '[' );
foreach( var person in PeopleListEnumerator )
{
if( result.Length > 1 )
result.Append( ',' );
result.Append( person.ToString() );
}
result.Append( ']' );
Джон Скит написал Умные Перечисления чтобы обеспечить такого рода функциональность, и они являются частью Неправильное приготовление библиотека.
Тем не менее, ваш конкретный пример лучше всего решается с помощью String.Подход Join(), как указывали многие другие.Написание общего string Join(this IEnumerable<T>,string)
расширение не является сложным и затем может использоваться в любых других ситуациях без необходимости прибегать к раздражающим временным массивам.
Используя LINQ, вы можете сделать:
string s =
string.Format("[{0}]", string.Join(",",PeopleListEnumerator.Select(p => p.ToString()).ToArray()));
Я обнаружил, что определяю и использую локальную переменную "bool first", например:
string s = "[";
bool first = true;
foreach (var person in PeopleListEnumerator) {
if (first)
first = false;
else
s += ",";
s += person.ToString();
}
s += "]";
Этот код точно соответствует тому, чего вы действительно хотите достичь:
StringBuilder s = new StringBuilder("[");
string delimiter = "";
foreach (var person in PeopleListEnumerator) {
s.Append(delimiter).Append(person.ToString());
delimiter = ",";
}
return s.Append("]").ToString();
Способ, которым я бы освежевал этого кота (да, есть так много способов), был бы:
StringBuilder sb = new StringBuilder();
foreach (var person in PeopleListEnumerator )
{
sb.AppendFormat(",{0}", person.ToString());
}
string s = "[" + sb.ToString().Substring(1) + "]";
Надеюсь, это поможет...
В .NET перечисления не имеют понятия порядка, кроме как по значению.Если вам нужно первое и последнее перечисление, я бы предложил явно определить, что представляют собой эти первое и последнее значения.Следующее перечисление является примером этого:
public enum PlayerType : byte
{
Starter = byte.MinValue,
RegularPlayer = 1,
BenchWarmer = 2,
Closer = byte.MaxValue
}
Затем вы можете выразить что-то похожее на следующее:
List<byte> values = new List<byte>((byte[])Enum.GetValues(typeof(PlayerType)));
PlayerType starter = (PlayerType)values.Min();
PlayerType closer = (PlayerType)values.Max();