c# - Pasando un solo elemento como IEnumerable <T>



7 Answers

Bueno, si el método espera un IEnumerable , debe pasar algo que es una lista, incluso si contiene un solo elemento.

paso

new T[] { item }

Como el argumento debería ser suficiente pienso

c# .net generics ienumerable

¿Hay una manera común de pasar un solo elemento de tipo T a un método que espera un IEnumerable<T> ? El lenguaje es C #, framework versión 2.0.

Actualmente estoy usando un método de ayuda (es .Net 2.0, así que tengo un montón de métodos de ayuda de proyección / proyección similares a LINQ), pero esto parece una tontería:

public static class IEnumerableExt
{
    // usage: IEnumerableExt.FromSingleItem(someObject);
    public static IEnumerable<T> FromSingleItem<T>(T item)
    {
        yield return item; 
    }
}

Otra forma sería, por supuesto, crear y rellenar una List<T> o un Array y pasarla en lugar de IEnumerable<T> .

[Editar] Como método de extensión podría llamarse:

public static class IEnumerableExt
{
    // usage: someObject.SingleItemAsEnumerable();
    public static IEnumerable<T> SingleItemAsEnumerable<T>(this T item)
    {
        yield return item; 
    }
}

¿Me estoy perdiendo de algo?

[Edit2] Encontramos que someObject.Yield() (como @Peter sugirió en los comentarios a continuación) es el mejor nombre para este método de extensión, principalmente por brevedad, por lo que aquí está junto con el comentario XML si alguien quiere agarrarlo:

public static class IEnumerableExt
{
    /// <summary>
    /// Wraps this object instance into an IEnumerable&lt;T&gt;
    /// consisting of a single item.
    /// </summary>
    /// <typeparam name="T"> Type of the object. </typeparam>
    /// <param name="item"> The instance that will be wrapped. </param>
    /// <returns> An IEnumerable&lt;T&gt; consisting of a single item. </returns>
    public static IEnumerable<T> Yield<T>(this T item)
    {
        yield return item;
    }
}



En C # 3 (sé que dijiste 2), puedes escribir un método de extensión genérico que podría hacer que la sintaxis sea un poco más aceptable:

static class IEnumerableExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T item)
    {
        yield return item;
    }
}

el código del cliente es entonces item.ToEnumerable() .




Este método auxiliar es trabajo para artículo o muchos.

public static IEnumerable<T> ToEnumerable<T>(params T[] items)
{
    return items;
}    



Aunque es excesivo para un método, creo que algunas personas pueden encontrar útiles las extensiones interactivas.

Las extensiones interactivas (Ix) de Microsoft incluyen el siguiente método.

public static IEnumerable<TResult> Return<TResult>(TResult value)
{
    yield return value;
}

Que se puede utilizar como tal:

var result = EnumerableEx.Return(0);

Ix agrega una nueva funcionalidad que no se encuentra en los métodos de extensión Linq originales, y es un resultado directo de la creación de las Extensiones reactivas (Rx).

Piensa, Linq Extension Methods + Ix = Rx para IEnumerable .

Puede encontrar tanto Rx como Ix en CodePlex .




Esto es 30% más rápido que el yield o Enumerable.Repeat cuando se usa en foreach debido a esta optimización del compilador de C # , y del mismo rendimiento en otros casos.

public struct SingleSequence<T> : IEnumerable<T> {
    public struct SingleEnumerator : IEnumerator<T> {
        private readonly SingleSequence<T> _parent;
        private bool _couldMove;
        public SingleEnumerator(ref SingleSequence<T> parent) {
            _parent = parent;
            _couldMove = true;
        }
        public T Current => _parent._value;
        object IEnumerator.Current => Current;
        public void Dispose() { }

        public bool MoveNext() {
            if (!_couldMove) return false;
            _couldMove = false;
            return true;
        }
        public void Reset() {
            _couldMove = true;
        }
    }
    private readonly T _value;
    public SingleSequence(T value) {
        _value = value;
    }
    public IEnumerator<T> GetEnumerator() {
        return new SingleEnumerator(ref this);
    }
    IEnumerator IEnumerable.GetEnumerator() {
        return new SingleEnumerator(ref this);
    }
}

en esta prueba:

    // Fastest among seqs, but still 30x times slower than direct sum
    // 49 mops vs 37 mops for yield, or c.30% faster
    [Test]
    public void SingleSequenceStructForEach() {
        var sw = new Stopwatch();
        sw.Start();
        long sum = 0;
        for (var i = 0; i < 100000000; i++) {
            foreach (var single in new SingleSequence<int>(i)) {
                sum += single;
            }
        }
        sw.Stop();
        Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds}");
        Console.WriteLine($"Mops {100000.0 / sw.ElapsedMilliseconds * 1.0}");
    }



Puede que esto no sea mejor, pero es genial:

Enumerable.Range(0, 1).Select(i => item);



La forma más fácil que diría sería new T[]{item}; ; No hay sintaxis para hacer esto. El equivalente más cercano que se me ocurre es la palabra clave params , pero, por supuesto, eso requiere que usted tenga acceso a la definición del método y solo se puede utilizar con matrices.




Related