c# destructuring c#-7.0

¿C#7 tiene matriz/desestructuración enumerable?



destructuring c#-7.0 (6)

En C # necesitarás escribir el tuyo, como este que estoy usando:

public static class ArrayExtensions { public static void Deconstruct<T>(this T[] array, out T first, out T[] rest) { first = array.Length > 0 ? array[0] : default(T); rest = array.Skip(1).ToArray(); } public static void Deconstruct<T>(this T[] array, out T first, out T second, out T[] rest) => (first, (second, rest)) = array; public static void Deconstruct<T>(this T[] array, out T first, out T second, out T third, out T[] rest) => (first, second, (third, rest)) = array; public static void Deconstruct<T>(this T[] array, out T first, out T second, out T third, out T fourth, out T[] rest) => (first, second, third, (fourth, rest)) = array; public static void Deconstruct<T>(this T[] array, out T first, out T second, out T third, out T fourth, out T fifth, out T[] rest) => (first, second, third, fourth, (fifth, rest)) = array; // .. etc. }

Entonces simplemente haz:

var (first, second,_ , rest) = new[] { 1, 2, 3, 4 }

En Javascript ES6, puedes destruir matrices como esta:

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

donde a es el primer elemento de la matriz, b es el segundo y rest es una matriz con los elementos restantes.

Sé que en C # 7 puedes destruir tuplas durante la asignación, pero no pude encontrar nada relacionado con la desestructuración de matrices / enumerables como esto:

var (a,b) = someTuple;

Tengo un IEnumerable donde necesito el primer y segundo elementos como variables, y necesito el resto de los elementos como otro IEnumerable. Tengo una solución, pero siento que la desestructuración se verá más limpia.


Lo que estás describiendo es generalmente conocido en lenguajes funcionales como "contras", que a menudo toma la forma:

let head :: tail = someCollection

Propuse que se agregara a C # , pero no recibió una respuesta muy favorable. Así que escribí el mío, que puede usar a través del paquete succinc <T> nuget .

Utiliza la deconstrucción para lograr esa división de la cabeza y la cola de cualquier IEnumerable<T> . Las deconstrucciones se pueden anidar, por lo que puede usarlas para extraer múltiples elementos de una sola vez:

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

Esto podría proporcionar la funcionalidad que está buscando.


No hay una sintaxis especial para ello en el idioma.

Sin embargo, podría aprovechar la sintaxis de la tupla para llegar a este

class Program { static void Main(string[] args) { int[] ints = new[] { 1, 2, 3 }; var (first, second, rest) = ints.Destruct2(); } } public static class Extensions { public static (T first, T[] rest) Desctruct1<T>(this T[] items) { return (items[0], items.Skip(1).ToArray()); } public static (T first, T second, T[] rest) Destruct2<T>(this T[] items) { return (items[0], items[1], items.Skip(2).ToArray()); } }

(que debe extenderse con el manejo de errores para escenarios de error obvios antes de ser utilizado en el código de producción).


No no hay. Sin embargo, no es muy difícil hacer algo similar.

¿Qué pasa con un método de extensión como este:

public static class EX { public static void Destructure<T>(this T[] items, out T t0) { t0 = items.Length > 0 ? items[0] : default(T); } public static void Destructure<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); } }

Y puedes usarlo así:

int[] items = { 1, 2 }; items.Destructure(out int t0);

El inconveniente es que necesita un método de extensión por cada número de artículos que devolver. Entonces, si tiene más de unas pocas variables para devolver, este método podría no ser muy útil.

Tenga en cuenta que dejé de revisar la longitud y las cosas relacionadas, pero supongo que usted entiende lo que hay que hacer.


Realmente rápido: No.

C # no soporta la desestructuración para Arrays todavía.

Actualmente, tampoco puedo encontrar ninguna información de esto en la hoja de ruta. Parece que habrá mucha espera involucrada hasta que obtengamos este azúcar sintáctico por defecto.

Como @Nekeniehl agregó en los comentarios, se puede implementar aunque: gist.github.com/waf/280152ab42aa92a85b79d6dbc812e68a


Resulta que no solo las tuplas se pueden deconstruir sino que cualquier tipo que tenga el método estático Deconstruct (o extensión) con la firma correspondiente. Hacer la deconstrucción correctamente para IEnumerable no es trivial (vea la biblioteca sugerida por David Arno en los comentarios), así que veamos cómo funciona con IList simple (la implementación es irrelevante, esta es por ejemplo y por supuesto puede ser mejor / diferente):

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

Luego (después de agregar una declaración de uso relevante si es necesario) puede usar exactamente la sintaxis que desea:

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

O puede encadenar la deconstrucción de esta manera (porque el último valor devuelto se puede deconstruir):

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

Con la última versión, puede deconstruir cualquier cantidad de ítems usando un solo método Deconstruct (el que devuelve el primer ítem y el resto).

Para uso real de IEnumerables, sugeriría no volver a implementar la rueda y usar la biblioteca de David Arno mencionada anteriormente.