95 votes

Est-ce que C # 7 a une déstructuration de tableau / énumérable?

En Javascript ES6, vous êtes en mesure de se déstructurent les tableaux comme ceci:

const [a,b,...rest] = someArray;

a est le premier élément dans le tableau, b la deuxième, et rest est un tableau avec les éléments restants.

Je sais en C#7, que vous pouvez se déstructurent les tuples lors de l'affectation, mais ne pouvait pas trouver quelque chose liée à la déstructuration des tableaux/enumerables comme ceci:

var (a,b) = someTuple;

J'ai un IEnumerable où j'ai besoin de la première et deuxième éléments variables, et j'ai besoin du reste des éléments comme un autre IEnumerable. J'ai une solution, mais le sentiment que déstructuration va regarder plus propre.

78voto

Evk Points 17804

Il s'avère non seulement les tuples peuvent être déconstruit, mais n'importe quel type qui a Deconstruct statique (ou l'extension) méthode avec signature correspondante. Faire déconstruction correctement pour IEnumerable n'est pas trivial (voir la bibliothèque proposé par David Arno dans les commentaires), donc nous allons voir comment il fonctionne avec un simple IList à la place (mise en œuvre n'est pas pertinent, c'est un exemple et peut être mieux/différent):

public static class Extensions {
    public static void Deconstruct<T>(this IList<T> list, out T first, out IList<T> rest) {

        first = list.Count > 0 ? list[0] : default(T); // or throw
        rest = list.Skip(1).ToList();
    }

    public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out IList<T> rest) {
        first = list.Count > 0 ? list[0] : default(T); // or throw
        second = list.Count > 1 ? list[1] : default(T); // or throw
        rest = list.Skip(2).ToList();
    }
}

Ensuite (après l'ajout pertinentes à l'aide de déclaration si nécessaire) vous pouvez utiliser exactement la syntaxe que vous voulez:

var list = new [] {1,2,3,4};
var (a,rest) = list;
var (b,c,rest2) = list;

Ou vous pouvez la chaîne de la déconstruction comme ça (parce que la valeur retournée peut lui-même être décomposé):

 var (a, (b, (c, rest))) = list;

Avec la dernière version, vous pouvez démonter pour n'importe quel nombre d'éléments à l'aide unique, Deconstruct méthode (celle qui renvoie le premier élément et le reste).

Pour l'utilisation réelle pour IEnumerables je vous suggère de ne pas ré-écrire de la roue et l'utilisation de David Arno de la bibliothèque de l'mentionnés ci-dessus.

25voto

David Arno Points 15499

Ce que vous décrivez est généralement connue dans les langages fonctionnels comme des "cons", qui prend souvent la forme:

let head :: tail = someCollection

J'ai proposé cet être ajouté à C#, mais il n'a pas reçu des commentaires favorables. J'ai donc écrit mon propre, que vous pouvez utiliser via le Succinc<T> package nuget.

Il utilise la déconstruction de réaliser que la division de la tête et de la queue de tout IEnumerable<T>. Déconstruit peuvent être imbriquées, de sorte que vous pouvez l'utiliser pour extraire plusieurs éléments en une seule fois:

var (a, (b, rest)) = someArray;

Cela pourrait fournir la fonctionnalité que vous êtes après.

25voto

Patrick Hofman Points 22166

Si vous voulez une solution entièrement intégrée avec le langage C# fonctionnalités, de l'utilisation Evk réponse, qui cache quelques de la mise en œuvre du détail. Si vous ne vous inquiétez pas à ce sujet, vous pouvez utiliser l'une des réponses.


À ma connaissance, il ne l'est pas. Cependant, il n'est pas très dur de faire quelque chose de similaire.

Ce qui sur une extension de la méthode comme ceci:

public static class EX
{
    public static void Deconstruct<T>(this T[] items, out T t0)
    {
        t0 = items.Length > 0 ? items[0] : default(T);
    }

    public static void Deconstruct<T>(this T[] items, out T t0, out T t1)
    {
        t0 = items.Length > 0 ? items[0] : default(T);
        t1 = items.Length > 1 ? items[1] : default(T);
    }
}

Et vous pouvez l'utiliser comme ceci:

int[] items = { 1, 2 };

items.Deconstruct(out int t0);

L'inconvénient, c'est que vous avez besoin d'une extension de la méthode par nombre d'articles à retourner. Donc, si vous avez un certain nombre de variables pour le retour, cette méthode peut ne pas être très utile.

Note que j'ai laissé de côté la vérification de la longueur, et les choses liées, mais vous comprenez ce qui doit être fait, je suppose.

16voto

Frederic Points 117

Pour étendre les solutions suggérées par d'autres contributeurs, je fournis une réponse utilisant IEnumerable. Cela n’est peut-être pas optimisé mais cela fonctionne assez bien.

 public static class IEnumerableExt
{
    public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out IEnumerable<T> rest)
    {
        first = seq.FirstOrDefault();
        rest = seq.Skip(1);
    }

    public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out T second, out IEnumerable<T> rest)
        => (first, (second, rest)) = seq;

    public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out T second, out T third, out IEnumerable<T> rest)
        => (first, second, (third, rest)) = seq;

    public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out T second, out T third, out T fourth, out IEnumerable<T> rest)
        => (first, second, third, (fourth, rest)) = seq;

    public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out T second, out T third, out T fourth, out T fifth, out IEnumerable<T> rest)
        => (first, second, third, fourth, (fifth, rest)) = seq;
}
 

Ensuite, utilisez simplement ces déconstructeurs comme ceci:

 var list = new[] { 1, 2, 3, 4 };
var (a, b, rest1) = list;
var (c, d, e, f, rest2) = rest1;
Console.WriteLine($"{a} {b} {c} {d} {e} {f} {rest2.Any()}");
// Output: 1 2 3 4 0 0 False
 

15voto

NikxDa Points 2099

Vraiment rapide: No.

C# ne prend pas en charge déstructurant pour les Tableaux encore.

Actuellement, je ne peux pas trouver toutes les informations sur la feuille de route, soit. Semble comme il y aura beaucoup d'attente impliqués jusqu'à ce que nous obtenir ce sucre syntaxique par défaut.

Comme @Nekeniehl ajouté dans les commentaires, il peut être mis en œuvre si: gist.github.com/waf/280152ab42aa92a85b79d6dbc812e68a

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X