Подтвердить что ты не робот

Есть ли что-то похожее на singletonList в С#

Java имеет Collections.singletonList(T), который возвращает List<T> ровно один элемент. Есть ли что-то подобное в С#, которое возвращает IList?

4b9b3361

Ответ 1

Чтобы ответить на ваш вопрос, нет. К сожалению, ничего не встроено, хотя часто бывает полезно при работе с IEnumerable. Вам придется сворачивать самостоятельно.

Обновление

Вместо использования обходных решений здесь приведен пример эффективного и неизменяемого SingletonList, который реализует IList<T>:

Использование

SingletonList<int> bling = new SingletonList<int>(10);    

код

public class SingletonList<T> : IList<T>
{
    private readonly T _item;

    public SingletonList(T item)
    {
        _item = item;
    }

    public IEnumerator<T> GetEnumerator()
    {
        yield return _item;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Add(T item)
    {
        throw new NotSupportedException("Add not supported.");
    }

    public void Clear()
    {
        throw new NotSupportedException("Clear not supported.");
    }

    public bool Contains(T item)
    {
        if (item == null) return _item == null;

        return item.Equals(_item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        if (array == null) throw new ArgumentNullException("array");

        array[arrayIndex] = _item;
    }

    public bool Remove(T item)
    {
        throw new NotSupportedException("Remove not supported.");
    }

    public int Count
    {
        get { return 1; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }

    public int IndexOf(T item)
    {
        return Contains(item) ? 0 : -1;
    }

    public void Insert(int index, T item)
    {
        throw new NotSupportedException("Insert not supported.");
    }

    public void RemoveAt(int index)
    {
        throw new NotSupportedException("RemoveAt not supported.");
    }

    public T this[int index]
    {
        get
        {
            if (index == 0) return _item;

            throw new IndexOutOfRangeException();
        }
        set { throw new NotSupportedException("Set not supported."); }
    }
} 

Ответ 2

Array реализует IList; и длина не может быть изменена с помощью Add (as ReadOnly is true).

Таким образом, SingletonList<int> может быть реализовано так же легко, как:

var slist = new int[] { 5 };

Возможно, вы захотите обернуть его в System.Collections.ObjectModel.ReadOnlyCollection<T>, чтобы одно значение не могло быть изменено (если список Java Singleton работает так). Например.

var slist = new System.Collections.ObjectModel.ReadOnlyCollection<int>(new int[] { 5 });

Вы также можете создать метод расширения.

public static IList<T> AsSingletonList<T>(this IEnumerable<T> source)
{
    foreach (var item in source)
    {
        return new System.Collections.ObjectModel.ReadOnlyCollection<T>(new T[] { item });
    }
    return new System.Collections.ObjectModel.ReadOnlyCollection<T>(new T[] { default(T) });
}

Или тот, который утверждает, что в источнике есть ровно одно значение:

public static IList<T> AsSingletonList<T>(this IEnumerable<T> source)
{
    IList<T> result = null;
    foreach (var item in source)
    {
        if (result != null)
            throw new ArgumentOutOfRangeException("source", "Source had more than one value.");
        result = new System.Collections.ObjectModel.ReadOnlyCollection<T>(new T[] { item });
    }

    if (result == null)
        throw new ArgumentOutOfRangeException("source", "Source had no values.");
    return result;
}

Изменить: используется ReadOnlyCollection<T>, чтобы предотвратить мутацию одного значения.

Примечание. Хотя я думаю, что другие ответы верны, List<T> по умолчанию имеет емкость 10 - это немного расточительно.

Ответ 3

public static class IListExtensions
{
    public static IList<T> SingletonList<T>(this IList<T> iList, T item)
    {        
        return Enumerable.Range(0, 1).Select(i => item).ToList().AsReadOnly();

        // or
        var Result = new List<T>();
        Result.Add(item);
        return Result.AsReadOnly();
    }
}

Ответ 4

В С# вы можете использовать инициализатор списка с одним элементом:

var x = new List<int> { 3 };

В отличие от singletonList, этот список изменчив.

Ответ 5

Это первое для меня: я даю ответ... то, что я должен сказать, не приводит к комментарию, imho... к вопросу, который, я думаю, я не совсем понимаю... в чтобы лучше понять вопрос. Рассмотрим:

    public class singletonList<T> : List<T>
    {
        public singletonList(T theValue) { base.Add(theValue); }

        public new void Add(T anotherValue) {}

        public new void AddRange(T anotherValue) {}

        public new void Clear() {}

        public new void Insert(int index, T anotherValue) {}

        public new void ToArray() {}
    }

Это создаст новый список любого типа, который допускает существование только одного экземпляра его значения-типа внутри Списка. Очевидно, что он не полностью "сглаживается", поскольку вы все равно можете использовать команды "InsertRange" и другие команды для изменения списка.

Здесь тестовое подтверждение его "неизменяемости" для внутренних операторов List, замаскированных с помощью "new" в своих объявлениях.

    var q = new singletonList<int>(99);
    q.Add(100);
    q.Clear();
    q.Insert(0, 788);

Я сомневаюсь, что это то, чего хочет OP, но мне любопытно, если это возможно, встретить OP spec в любом случае.

Несмотря на объяснения рода ChibaCity, я все еще совершенно озадачен тем, почему кто-то захочет использовать Список, содержащий только один элемент.

Заранее благодарим за то, что вы просветили меня, и если стоимость просветления - это потеря голосов или лицо... никаких проблем; в моем возрасте я не бегаю ни за что, кроме пребывания на месте, и лицо лучше всего забыто:)