开发者

Is there something similar to singletonList in C#

开发者 https://www.devze.com 2023-03-29 14:11 出处:网络
Java has Collections.singletonList(T) which returns a List<T> of exactly one element. Is the开发者_如何转开发re something similar in C# that returns an IList?IEnumerable<T> enumerable = En

Java has Collections.singletonList(T) which returns a List<T> of exactly one element. Is the开发者_如何转开发re something similar in C# that returns an IList?


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

Creates an IEnumerable with one element.


Array implements IList; and the length cannot be modified via Add (as ReadOnly is true).

Thus, SingletonList<int> could be implemented as easily as:

var slist = new int[] { 5 };

You may want to wrap it in a System.Collections.ObjectModel.ReadOnlyCollection<T> so that the single value cannot be changed (if the Java Singleton list works like this). E.g.

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

You can also create an extension method.

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

Or one that asserts there is exactly one value in the source:

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

Edit: Used ReadOnlyCollection<T> to prevent mutation of the single value.

Note: While I think the other answers are correct, the List<T> by default has a capacity of 10 - which is a tiny bit wasteful.


To answer your question, no. Sadly there is nothing built in, although it would often be useful when working with IEnumerable. You'll have to roll your own.

Update

Instead of using workarounds, here's an example of an efficient and immutable SingletonList that implements IList<T>:

Usage

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

Code

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."); }
    }
} 


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


In C#, you can use a list initializer with one element:

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

Contrary to singletonList, this list is mutable. If you want something immutable, you can call AsReadOnly() on the resulting object:

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


I passed a new[] { alreadyDeclaredVariable } into the function. That's one way to do it, just making an in-place array of 1 element.


This is a first for me: I am submitting an answer ... what I have to say does not lead itself to a comment, imho ... to a question which I think I do not fully understand ... in order to better understand the question. Consider:

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

This will create a new List of whatever Type which allows only one instance of its value-Type to exist inside the List. Obviously it's not fully 'fleshed-out' since you could still use 'InsertRange' and other List altering commands.

Here's a test verifying its 'immutable' for the internal List operators masked-out by the use of 'new' in their declarations.

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

I doubt this is what the OP wants, but I am curious if this perhaps does, meet the OP's spec in any way.

In spite of ChibaCity's kind explanations, I am still utterly baffled why one would ever want to use a List that contained only one element.

Thanks in advance for educating me, and if the cost of enlightenment is loss of votes, or face ... no problem; at my age I am not running for anything except staying in place, and face is best forgotten :)

0

精彩评论

暂无评论...
验证码 换一张
取 消