在C#中有类似于singletonList的东西吗?

Mis*_*ble 14 c#

Java Collections.singletonList(T)只返回List<T>一个元素.C#中有类似的东西会返回IList吗?

Pat*_*ick 9

IEnumerable<T> enumerable = Enumerable.Repeat(t, 1);

用一个元素创建一个 IEnumerable。


Tim*_*oyd 7

要回答你的问题,不.遗憾的是,没有内置任何内容,尽管在使用IEnumerable时它通常很有用.你必须自己动手.

更新

这里有一个高效且不可变的SingletonList实现的代码,而不是使用变通方法IList<T>:

用法

SingletonList<int> bling = new SingletonList<int>(10);    
Run Code Online (Sandbox Code Playgroud)

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."); }
    }
} 
Run Code Online (Sandbox Code Playgroud)

  • @BillW这对于`IEnumerable <T>`情况很有用,因为它们是不可变的,但是,实现`IList <T>`是有问题的,因为`IList <T>`清楚地表明集合变异(例如Add,Remove,Insert等等,这与SingletonList的目标不一致.但是,`IList <T>`在BCL中用于不可变集合(参见`ReadOnlyCollection`),其中`IsReadOnly`属性是关键.这种情况很不幸,因为它破坏了LSP,即子类型在行为上不兼容,因为它们没有完全实现接口. (2认同)

Jon*_*son 6

Array实施IList; 和长度不能经由被修改Add(如ReadOnlytrue).

因此,SingletonList<int>可以像以下一样轻松实现:

var slist = new int[] { 5 };
Run Code Online (Sandbox Code Playgroud)

您可能希望将其包装在一起,System.Collections.ObjectModel.ReadOnlyCollection<T>以便无法更改单个值(如果Java Singleton列表的工作方式如此).例如

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

您还可以创建扩展方法.

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) });
}
Run Code Online (Sandbox Code Playgroud)

或者断言在源中只有一个值:

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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:用于ReadOnlyCollection<T>防止单个值的突变.

注意:虽然我认为其他答案是正确的,但List<T>默认情况下容量为10 - 这有点浪费.


Geo*_*ett 5

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();
    }
}
Run Code Online (Sandbox Code Playgroud)