visual una tipos studio programacion extraer ejemplos datos conversion codigos caracteres cadena c# arrays destructuring

una - tipos de datos en c#



Manejar el número variable de parámetros de salida con menos duplicación de código en C# (9)

Bueno, puedes cambiar tu método a algo como

public IEnumerable<string> ParseRemainders(string[] remainders) { var result = new List<string>(); ///... your logic here, fill list with your strings according to your needs return result; }

Estoy tratando de escribir una función que rellena las cadenas con el contenido de una matriz, o las pone a cero. El número de cadenas puede variar y no quiero agregar requisitos, ya que todas forman parte de la misma matriz o clase.

En C # no puedes combinar param y out . Por lo tanto, la única forma de hacer esto parece ser sobrecargar el método de esta manera:

public void ParseRemainders(string[] remainders, out string p1) { p1 = null; if ((remainders != null) && (remainders.Length > 0)) p1 = remainders[0]; } public void ParseRemainders(string[] remainders, out string p1, out string p2) { p1 = null; p2 = null; if (remainders != null) { ParseRemainders(remainders, out p1); if (remainders.Length > 1) p2 = remainders[1]; } } public void ParseRemainders(string[] remainders, out string p1, out string p2, out string p3) { p1 = null; p2 = null; p3 = null; if (remainders != null) { ParseRemainders(remainders, out p1, out p2); if (remainders.Length > 2) p3 = remainders[2]; } } .... and on forever ....

¿Cómo puedo evitar toda esta duplicación de código, idealmente aceptando un número arbitrario de parámetros?

Edición: esto es útil porque podría hacer, por ejemplo, ParseRemainders(remainders, out inputFileName, out outputFileName, out configFileName) y luego evitar tener que hacer manualmente

if (remainder.Length > 0) inputFileName = remainder[0]; if (remainder.Length > 1) outputFileName = remainder[1]; if (remainder.Length > 2) configFileName = remainder[2]; ...

Lo siento si esto no estaba claro, tenía un objetivo específico en mente, por lo que simplemente no devolví una List<> .

Conclusión: Gracias a Botond Balázs por la respuesta, en particular el indicio de que esto se llama "desestructuración de matrices". Como señalan, y como confirma esta pregunta, no es posible en la versión actual de C #: Asignación de destrucción : propiedades del objeto a variables en C #


Creo que esto se acerca bastante a lo que quieres. No necesita C # 7, funciona con cualquier tipo de elemento de datos y no se limita a matrices. Sin embargo, es posible que desee elegir mejores nombres que ValueReader / ReadValue.

static class Extensions { public static ValueReader<T> ReadValue<T>(this IEnumerable<T> source, out T value) { var result = new ValueReader<T>(source); result.ReadValue(out value); return result; } } class ValueReader<T> { IEnumerator<T> _enumerator; public ValueReader(IEnumerable<T> source) { if (source == null) source = new T[0]; _enumerator = source.GetEnumerator(); } public ValueReader<T> ReadValue(out T value) { bool hasNext = _enumerator.MoveNext(); value = hasNext ? _enumerator.Current : default(T); return this; } } static class TestApp { public static void Main() { var remainders = new string[] { "test1", "test2", "test3" }; string inputFileName, outputFileName, configFileName, willBeSetToNull; remainders .ReadValue(out inputFileName) .ReadValue(out outputFileName) .ReadValue(out configFileName) .ReadValue(out willBeSetToNull); } }


El enfoque de Andys está bien, pero devolvería una string[] porque debería tener el mismo tamaño que la matriz de entrada y también devolvería null si la matriz de entrada era null :

public string[] ParseRemainders(string[] remainders) { if(remainders == null) return null; var parsed = new string[remainders.Length]; for(int i = 0; i < remainders.Length; i++) parsed[i] = ParseRemainder(remainders[i]); return parsed; }

Para aclarar qué hace ParseRemainder (método diferente para una sola string ):

public string ParseRemainder(string remainder) { // parsing logic here... return "the parsing result of remainder"; }


Para completar, así es como puedes hacer este tipo de cosas en C # 7 (Visual Studio 2017):

string[] test = { "One", "Two", "Three", "Four", "Five" }; var (a, b, c) = (test[0], test[2], test[4]); Debug.Assert(a == "One"); Debug.Assert(b == "Three"); Debug.Assert(c == "Five");

La línea importante aquí es var (a, b, c) = (test[0], test[2], test[4]); que le muestra la forma abreviada de asignar varias variables diferentes de algunos elementos de una matriz.

Sin embargo, esto no ayuda con la asignación de nulos si la matriz no es lo suficientemente larga. Puedes solucionar este problema escribiendo una clase de ayuda:

public sealed class ElementsOrNull<T> where T: class { readonly IList<T> array; public ElementsOrNull(IList<T> array) { this.array = array; } public T this[int index] { get { if (index < array.Count) return array[index]; return null; } } }

Y entonces:

string[] test = { "One", "Two", "Three", "Four", "Five" }; var t = new ElementsOrNull<string>(test); var (a, b, c) = (t[0], t[2], t[6]); Debug.Assert(a == "One"); Debug.Assert(b == "Three"); Debug.Assert(c == null);

Pero estoy seguro de que la mayoría de las personas (yo incluido) pensarán que eso es más problema de lo que vale la pena.


Parece que estás intentando complicar en exceso una simple comprobación de nulos, solo vuelve a lo básico y hazlo simple:

public string GetRemainder(string[] remainders, int index) { if ((remainders != null) && (remainders.Length > index)) return remainders[index]; return null; }

Uso:

var inputFileName = GetRemainder(remainder, 0); var outputFileName = GetRemainder(remainder, 1); var configFileName = GetRemainder(remainder, 2);


Por su descripción, supongo que su caso de uso sería algo similar a:

public void SomeMethod( ... ) { string p1; string p2; .... ParseRemainders(string[] remainders, out string p1, out string p2); ... } public void SomeOtherMethod( ... ) { string p1; string p2; string p3; .... ParseRemainders(string[] remainders, out string p1, out string p2, out string p3); ... }

No necesitas devolver cuerdas de esta manera. Como ya se señaló en otras respuestas / comentarios, simplemente puede devolver una serie de cadenas:

string[] ParseRemainders(string[] remainders) { var result = new string[remainder.Length]; result[0] = //whatever p1 would be result[1] = //whatever p2 would be //etc. }

Y lo usarías así:

public void SomeMethod( ... ) { .... var parsed = ParseRemainders(string[] remainders); string p1 = parsed[0]; string p2 = parsed[1]; .... }

Eso se ve mucho mejor.


Si te entiendo correctamente, tu caso de uso se vería así:

var remainders = new[] { "a", "b", "c" }; string a, b, c; ParseRemainders(remainders, a, b, c); // after this, a == "a", b == "b" and c == "c"

La característica que desea tener en C # se llama desestructuración de matrices , como en JavaScript:

var remainders = ["a", "b", "c"]; var [a, b, c] = remainders; // after this, a == "a", b == "b" and c == "c"

Desafortunadamente, por lo que yo sé,

esto no se puede resolver de una manera general usando C # .

Sin embargo, C # 7 tendrá una desestructuración de tuplas


Simplemente use un índice en la matriz, por ejemplo:

remainers[0]; //same as p1 remainers[1]; //same as p2 remainers[2]; //same as p3


Tomaría un enfoque diferente al de cualquiera de las respuestas hasta ahora.

static class Extensions { public static SafeArrayReader<T> MakeSafe<T>(this T[] items) { return new SafeArrayReader<T>(items); } } struct SafeArrayReader<T> { private T[] items; public SafeArrayReader(T[] items) { this.items = items; } public T this[int index] { get { if (items == null || index < 0 || index >= items.Length) return default(T); return items[index]; } } }

Ahí, ahora tienes una matriz que te da un valor predeterminado en lugar de lanzar:

var remainder = GetRemainders().MakeSafe(); var input = remainder[0]; var output = remainder[1]; var config = remainder[2];

Pan comido. ¿Tienes algún problema con la semántica de un tipo de datos? Haga un mejor tipo de datos que encapsule la semántica deseada .