C#中是否有类似于singletonList的东西?

20

Java有Collections.singletonList(T),它返回一个仅包含一个元素的List<T>。在C#中是否有类似的方法可以返回IList


1
根据@eyelesscactus54的说法,最简单的方法是:var mySingletonIlist = new[]{myVariable}; - Jack
7个回答

11

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

使用一个元素创建IEnumerable。


10

Array 实现了 IList 接口;且由于 ReadOnlytrue,因此无法通过 Add 修改其长度。

因此,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,这有点浪费空间。


-1 这不会创建一个不可变的单项列表。您可以将结果转换回数组,然后更改值。 - Tim Lloyd

8
为了回答你的问题,很遗憾没有内置的方法可以实现,尽管在使用IEnumerable时经常会很有用。你需要自己编写代码。
更新:
不必使用变通方法,下面是一个高效且不可变的SingletonList示例,实现了IList:
用法:
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."); }
    }
} 

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();
    }
}

添加 AsReadOnly() 并且它是不可变的。所以:return Enumerable.Range(0, 1).Select(i => item).ToList().AsReadOnly() - ZoolWay

3
在C#中,您可以使用一个元素的列表初始化器:
var x = new List<int> { 3 };

singletonList相反,这个列表是可以改变的。如果您想要不可变的对象,可以在结果对象上调用AsReadOnly()

// Looks strange, but, yes, this is actually valid C#.
var x = new List<int> { 3 }.AsReadOnly();

2
我把new[] { alreadyDeclaredVariable }传递给了函数。这是一种方法,只需创建一个由1个元素组成的现场数组即可。

感谢您指出数组的类型可以被推断。 - teichert

1
这对我来说是第一次:我正在提交一个答案...我认为我的话不适合作为评论...针对一个我认为自己并没有完全理解的问题...为了更好地理解这个问题。请考虑:
    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”和其他列表更改命令。

这里有一个测试,验证了它对于由于在声明中使用“new”而被屏蔽的内部列表运算符是“不可变”的。

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

我怀疑这不是OP所想要的,但我很好奇这是否在任何方面满足了OP的规格。

尽管ChibaCity友好的解释,我仍然完全不明白为什么有人会想使用只包含一个元素的列表。

提前感谢您对我的教育,如果启示成本是失去票数或面子......没问题;在我这个年纪,我除了待在原地,再也不会去做其他任何事情,而且最好忘记面子 :)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接