472 Stimmen

Übergabe eines einzelnen Elements als IEnumerable<T>

Gibt es eine gängige Methode, um ein einzelnes Element vom Typ T zu einer Methode, die eine IEnumerable<T> Parameter? Sprache ist C#, Framework Version 2.0.

Derzeit verwende ich eine Hilfsmethode (es ist .Net 2.0, so habe ich eine ganze Reihe von Casting/Projecting-Hilfsmethoden ähnlich wie LINQ), aber dies scheint einfach dumm:

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

Eine andere Möglichkeit wäre natürlich die Erstellung und Befüllung einer List<T> oder ein Array und übergeben Sie es anstelle von IEnumerable<T> .

[Bearbeiten] Als Erweiterungsmethode könnte sie benannt werden:

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

Übersehe ich hier etwas?

[Bearbeiten2] Wir fanden someObject.Yield() (wie @Peter in den Kommentaren unten vorschlug) für den besten Namen für diese Erweiterungsmethode, vor allem der Kürze halber, also hier ist er zusammen mit dem XML-Kommentar, falls jemand ihn verwenden möchte:

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

7voto

cwharris Punkte 17356

Obwohl es für eine Methode zu viel ist, glaube ich, dass einige Leute die interaktiven Erweiterungen nützlich finden könnten.

Die Interactive Extensions (Ix) von Microsoft beinhalten die folgende Methode.

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

Das kann folgendermaßen genutzt werden:

var result = EnumerableEx.Return(0);

Ix fügt neue Funktionen hinzu, die in den ursprünglichen Linq-Erweiterungsmethoden nicht enthalten sind, und ist ein direktes Ergebnis der Entwicklung der Reactive Extensions (Rx).

Denken Sie nach, Linq Extension Methods + Ix = Rx para IEnumerable .

Sie können beide finden Rx und Ix auf CodePlex .

5voto

mattica Punkte 315

Kürzlich habe ich die gleiche Frage in einem anderen Beitrag gestellt

Gibt es eine Möglichkeit, eine C#-Methode aufzurufen, die eine IEnumerable<T> mit einem einzigen Wert erfordert? ...mit Benchmarking .

Ich wollte, dass die Leute, die hier vorbeikommen, den kurzen Benchmark-Vergleich sehen, der in diesem neueren Beitrag für 4 der in diesen Antworten vorgestellten Ansätze gezeigt wird.

Es scheint, dass das Schreiben von new[] { x } in den Argumenten für die Methode ist die kürzeste und schnellste Lösung.

5voto

Lance U. Matthews Punkte 14378

Abzulegen unter "Nicht unbedingt ein gut Lösung, aber trotzdem...eine Lösung" oder "Dumme LINQ-Tricks", könnten Sie kombinieren Enumerable.Empty<>() con Enumerable.Append<>() ...

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Append("Hello, World!");

...oder Enumerable.Prepend<>() ...

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Prepend("Hello, World!");

Die letzten beiden Methoden sind seit .NET Framework 4.7.1 und .NET Core 1.0 verfügbar.

Dies ist eine praktikable Lösung, wenn man realmente die Absicht haben, bestehende Methoden zu verwenden, anstatt ihre eigenen zu schreiben, obwohl ich mir nicht sicher bin, ob dies mehr oder weniger deutlich ist als die Enumerable.Repeat<>() Lösung . Dies ist definitiv längerer Code (was zum Teil daran liegt, dass die Inferenz von Typparametern nicht möglich ist für Empty<>() ) und erzeugt doppelt so viele Enumerator-Objekte.

Abschließend noch eine Antwort auf die Frage "Wussten Sie, dass es diese Methoden gibt?", Array.Empty<>() könnte ersetzt werden durch Enumerable.Empty<>() aber es ist schwer zu behaupten, dass das die Situation ... besser macht.

4voto

Ken Lange Punkte 65

Das hier ist vielleicht nicht besser, aber irgendwie cool:

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

4voto

Jason C Punkte 35780

Manchmal mache ich das, wenn ich schelmisch bin:

"_".Select(_ => 3.14)  // or whatever; any type is fine

Das ist das Gleiche mit weniger shift Tastendrücke, heh:

from _ in "_" select 3.14

Für eine Utility-Funktion finde ich dies die am wenigsten ausführliche, oder zumindest mehr Selbst-Dokumentation als ein Array, obwohl es mehrere Werte gleiten lassen wird; als ein Plus kann es als eine lokale Funktion definiert werden:

static IEnumerable<T> Enumerate (params T[] v) => v;
// usage:
IEnumerable<double> example = Enumerate(1.234);

Hier sind alle anderen Möglichkeiten, die mir eingefallen sind ( hier lauffähig ):

using System;
using System.Collections.Generic;
using System.Linq;

public class Program {

    public static IEnumerable<T> ToEnumerable1 <T> (T v) {
        yield return v;
    }

    public static T[] ToEnumerable2 <T> (params T[] vs) => vs;

    public static void Main () {
        static IEnumerable<T> ToEnumerable3 <T> (params T[] v) => v;
        p( new string[] { "three" } );
        p( new List<string> { "three" } );
        p( ToEnumerable1("three") ); // our utility function (yield return)
        p( ToEnumerable2("three") ); // our utility function (params)
        p( ToEnumerable3("three") ); // our local utility function (params)
        p( Enumerable.Empty<string>().Append("three") );
        p( Enumerable.Empty<string>().DefaultIfEmpty("three") );
        p( Enumerable.Empty<string>().Prepend("three") );
        p( Enumerable.Range(3, 1) ); // only for int
        p( Enumerable.Range(0, 1).Select(_ => "three") );
        p( Enumerable.Repeat("three", 1) );
        p( "_".Select(_ => "three") ); // doesn't have to be "_"; just any one character
        p( "_".Select(_ => 3.3333) );
        p( from _ in "_" select 3.0f );
        p( "a" ); // only for char
        // these weren't available for me to test (might not even be valid):
        //   new Microsoft.Extensions.Primitives.StringValues("three")

    }

    static void p <T> (IEnumerable<T> e) =>
        Console.WriteLine(string.Join(' ', e.Select((v, k) => $"[{k}]={v,-8}:{v.GetType()}").DefaultIfEmpty("<empty>")));

}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X