¿Cómo puedo devolver múltiples valores de una función en C #?

Leí la versión C ++ de esta pregunta, pero realmente no la entendí.

¿Puede alguien explicar claramente si se puede hacer y cómo?

Use la Tupla de .NET 4.0 + :

Por ejemplo:

public Tuple GetMultipleValue() { return Tuple.Create(1,2); } 

Las tuplas con dos valores tienen Item2 y Item2 como propiedades.

Ahora que C # 7 ha sido lanzado, puedes usar la nueva syntax Tuples incluida

 (string, string, string) LookupName(long id) // tuple return type { ... // retrieve first, middle and last from data storage return (first, middle, last); // tuple literal } 

que luego podría usarse así:

 var names = LookupName(id); WriteLine($"found {names.Item1} {names.Item3}."); 

También puede proporcionar nombres a sus elementos (para que no sean “Artículo1”, “Artículo2”, etc.). Puede hacerlo agregando un nombre a la firma o a los métodos de devolución:

 (string first, string middle, string last) LookupName(long id) // tuple elements have names 

o

 return (first: first, middle: middle, last: last); // named tuple elements in a literal 

También se pueden deconstruir, lo cual es una nueva característica bastante agradable:

 (string first, string middle, string last) = LookupName(id1); // deconstructing declaration 

Echa un vistazo a este enlace para ver más ejemplos sobre lo que se puede hacer 🙂

Puedes usar tres formas diferentes

1. parámetros de ref / out

usando ref:

 static void Main(string[] args) { int a = 10; int b = 20; int add = 0; int multiply = 0; Add_Multiply(a, b, ref add, ref multiply); Console.WriteLine(add); Console.WriteLine(multiply); } private static void Add_Multiply(int a, int b, ref int add, ref int multiply) { add = a + b; multiply = a * b; } 

utilizando:

 static void Main(string[] args) { int a = 10; int b = 20; int add; int multiply; Add_Multiply(a, b, out add, out multiply); Console.WriteLine(add); Console.WriteLine(multiply); } private static void Add_Multiply(int a, int b, out int add, out int multiply) { add = a + b; multiply = a * b; } 

2. estructura / clase

usando struct:

 struct Result { public int add; public int multiply; } static void Main(string[] args) { int a = 10; int b = 20; var result = Add_Multiply(a, b); Console.WriteLine(result.add); Console.WriteLine(result.multiply); } private static Result Add_Multiply(int a, int b) { var result = new Result { add = a * b, multiply = a + b }; return result; } 

usando clase:

 class Result { public int add; public int multiply; } static void Main(string[] args) { int a = 10; int b = 20; var result = Add_Multiply(a, b); Console.WriteLine(result.add); Console.WriteLine(result.multiply); } private static Result Add_Multiply(int a, int b) { var result = new Result { add = a * b, multiply = a + b }; return result; } 

3. Tuple

Clase Tuple

 static void Main(string[] args) { int a = 10; int b = 20; var result = Add_Multiply(a, b); Console.WriteLine(result.Item1); Console.WriteLine(result.Item2); } private static Tuple Add_Multiply(int a, int b) { var tuple = new Tuple(a + b, a * b); return tuple; } 

C # 7 Tuples

 static void Main(string[] args) { int a = 10; int b = 20; (int a_plus_b, int a_mult_b) = Add_Multiply(a, b); Console.WriteLine(a_plus_b); Console.WriteLine(a_mult_b); } private static (int a_plus_b, int a_mult_b) Add_Multiply(int a, int b) { return(a + b, a * b); } 

No puedes hacer esto en C #. Lo que puedes hacer es tener un parámetro out o devolver tu propia clase (o struct si quieres que sea inmutable).

Usando el parámetro

 public int GetDay(DateTime date, out string name) { // ... } 

Usar clase personalizada (o struct)

 public DayOfWeek GetDay(DateTime date) { // ... } public class DayOfWeek { public int Day { get; set; } public string Name { get; set; } } 

Si quiere decir devolver múltiples valores, puede devolver una clase / estructura que contenga los valores que desea devolver, o usar la palabra clave “out” en sus parámetros, de esta forma:

 public void Foo(int input, out int output1, out string output2, out string errors) { // set out parameters inside function } 

El poster anterior es correcto. No puede devolver múltiples valores desde un método C #. Sin embargo, tienes un par de opciones:

  • Devuelve una estructura que contiene múltiples miembros
  • Devuelve una instancia de una clase
  • Use los parámetros de salida (usando las palabras clave out o ref )
  • Use un par de diccionario o clave-valor como resultado

Los pros y los contras aquí a menudo son difíciles de descubrir. Si devuelve una estructura, asegúrese de que sea pequeña porque las estructuras son del tipo de valor y pasan en la stack. Si devuelve una instancia de una clase, aquí hay algunos patrones de diseño que puede utilizar para evitar problemas: los miembros de las clases pueden modificarse porque C # pasa los objetos por referencia (no tiene ByVal como lo hizo en VB). )

Finalmente puede usar parámetros de salida, pero limitaría el uso de esto a escenarios cuando solo tiene un par (como 3 o menos) de parámetros; de lo contrario, las cosas se pondrán feas y difíciles de mantener. Además, el uso de parámetros de salida puede ser un inhibidor de la agilidad porque la firma de su método tendrá que cambiar cada vez que necesite agregar algo al valor devuelto, mientras que al devolver una instancia struct o class puede agregar miembros sin modificar la firma del método.

Desde un punto de vista arquitectónico, recomendaría no usar pares de valores-clave o diccionarios. Encuentro que este estilo de encoding requiere “conocimiento secreto” en el código que consume el método. Debe saber de antemano cuáles serán las claves y qué significan los valores, y si el desarrollador que trabaja en la implementación interna cambia la forma en que se crea el diccionario o KVP, podría crear fácilmente una cascada de fallas en toda la aplicación.

O devuelve una instancia de clase o utiliza parámetros de salida . Aquí hay un ejemplo de nuestros parámetros:

 void mymethod(out int param1, out int param2) { param1 = 10; param2 = 20; } 

Llámalo así:

 int i, j; mymethod(out i, out j); // i will be 20 and j will be 10 

Hay varias formas de hacer esto. Puede usar los parámetros de ref :

 int Foo(ref Bar bar) { } 

Esto pasa una referencia a la función, lo que permite que la función modifique el objeto en la stack del código de llamada. Si bien esto técnicamente no es un valor “devuelto”, es una forma de hacer que una función haga algo similar. En el código anterior, la función devolvería una bar modificación int y (potencialmente).

Otro enfoque similar es usar un parámetro de out . Un parámetro out es idéntico a un parámetro ref con una regla adicional, aplicada por el comstackdor. Esta regla es que si pasa un parámetro de out a una función, se requiere que esa función establezca su valor antes de regresar. Además de esa regla, un parámetro out funciona igual que un parámetro ref .

El enfoque final (y el mejor en la mayoría de los casos) es crear un tipo que encapsule ambos valores y permita que la función lo devuelva:

 class FooBar { public int i { get; set; } public Bar b { get; set; } } FooBar Foo(Bar bar) { } 

Este enfoque final es más simple y fácil de leer y entender.

En C # 4, podrá usar el soporte integrado para tuplas para manejar esto fácilmente.

Mientras tanto, hay dos opciones.

En primer lugar, puede usar los parámetros ref o out para asignar valores a sus parámetros, los cuales pasan a la rutina de llamadas.

Esto se ve así:

 void myFunction(ref int setMe, out int youMustSetMe); 

En segundo lugar, puede resumir los valores devueltos en una estructura o clase y pasarlos de nuevo como miembros de esa estructura. KeyValuePair funciona bien para 2: durante más de 2 necesitarás una clase o estructura personalizada.

No, no puede devolver múltiples valores desde una función en C # (para versiones inferiores a C # 7), al menos no de la manera en que lo puede hacer en Python.

Sin embargo, hay un par de alternativas:

Puede devolver una matriz de tipo de objeto con los múltiples valores que desee.

 private object[] DoSomething() { return new [] { 'value1', 'value2', 3 }; } 

Puedes usar out parámetros.

 private string DoSomething(out string outparam1, out int outparam2) { outparam1 = 'value2'; outparam2 = 3; return 'value1'; } 

En C # 7 hay una nueva syntax Tuple :

 static (string foo, int bar) GetTuple() { return ("hello", 5); } 

Puede devolver esto como un registro:

 var result = GetTuple(); var foo = result.foo // foo == "hello" 

También puede usar la nueva syntax de deconstructor:

 (string foo) = GetTuple(); // foo == "hello" 

Tenga cuidado con la serialización, sin embargo, todo esto es azúcar sintáctico: en el código comstackdo real, este será un Tupel (según la respuesta aceptada ) con Item2 y Item2 lugar de foo y bar . Eso significa que la serialización (o deserialización) usará esos nombres de propiedad en su lugar.

Entonces, para la serialización, declare una clase de registro y devuélvala en su lugar.

También nuevo en C # 7 es una syntax mejorada para out parámetros. Ahora puede declarar el out línea, que es más adecuado en algunos contextos:

 if(int.TryParse("123", out int result)) { // Do something with result } 

Sin embargo, la mayoría usará esto en las propias bibliotecas de .NET, en lugar de en sus propias funciones.

puedes probar este “KeyValuePair”

 private KeyValuePair GetNumbers() { return new KeyValuePair(1, 2); } var numbers = GetNumbers(); Console.WriteLine("Output : {0}, {1}",numbers.Key, numbers.Value); 

Salida:

Salida: 1, 2

Algunas de estas respuestas indican que se usa un parámetro, pero recomiendo no usarlo porque no funcionan con métodos asíncronos . Vea esto para más información.

Otras respuestas indicaron usar Tuple, que también recomendaría pero usando la nueva característica introducida en C # 7.0.

 (string, string, string) LookupName(long id) // tuple return type { ... // retrieve first, middle and last from data storage return (first, middle, last); // tuple literal } var names = LookupName(id); WriteLine($"found {names.Item1} {names.Item3}."); 

Más información se puede encontrar aquí .

Las clases, las estructuras, las colecciones y las matrices pueden contener valores múltiples. Los parámetros de salida y referencia también se pueden configurar en una función. La devolución de valores múltiples es posible en idiomas dynamics y funcionales mediante tuplas, pero no en C #.

Principalmente hay dos métodos ahí. 1. Usar los parámetros out / ref 2. Devolver una matriz de objetos

Aquí hay Two métodos básicos:

1) Uso de ‘ out ‘ como parámetro Puede usar ‘out’ para 4.0 y versiones menores también.

Ejemplo de ‘fuera’:

 using System; namespace out_parameter { class Program { //Accept two input parameter and returns two out value public static void rect(int len, int width, out int area, out int perimeter) { area = len * width; perimeter = 2 * (len + width); } static void Main(string[] args) { int area, perimeter; // passing two parameter and getting two returning value Program.rect(5, 4, out area, out perimeter); Console.WriteLine("Area of Rectangle is {0}\t",area); Console.WriteLine("Perimeter of Rectangle is {0}\t", perimeter); Console.ReadLine(); } } } 

Salida:

Área de rectángulo es 20

El perímetro del rectángulo es 18

* Nota: * La palabra clave de out describe parámetros cuyas ubicaciones de variables reales se copian en la stack del método llamado, donde esas mismas ubicaciones se pueden volver a escribir. Esto significa que el método de llamada accederá al parámetro modificado.

2) Tuple

Ejemplo de Tuple:

Devolución de valores múltiples de DataType con Tuple

 using System; class Program { static void Main() { // Create four-item tuple; use var implicit type. var tuple = new Tuple("perl", new string[] { "java", "c#" }, 1, new int[] { 2, 3 }); // Pass tuple as argument. M(tuple); } static void M(Tuple tuple) { // Evaluate the tuple's items. Console.WriteLine(tuple.Item1); foreach (string value in tuple.Item2) { Console.WriteLine(value); } Console.WriteLine(tuple.Item3); foreach (int value in tuple.Item4) { Console.WriteLine(value); } } } 

Salida

 perl java c# 1 2 3 

NOTA: El uso de Tuple es válido desde Framework 4.0 y superior . Tuple type es una class . Se asignará en una ubicación separada en el montón administrado en la memoria. Una vez que crea el Tuple , no puede cambiar los valores de sus fields . Esto hace que la Tuple parezca más a una struct .

Un método que toma un delegado puede proporcionar valores múltiples a la persona que llama. Esto toma prestado de mi respuesta aquí y usa un poco de la respuesta aceptada de Hadas .

 delegate void ValuesDelegate(int upVotes, int comments); void GetMultipleValues(ValuesDelegate callback) { callback(1, 2); } 

Las personas que llaman proporcionan un lambda (o una función nombrada) y intellisense ayuda al copiar los nombres de las variables del delegado.

 GetMultipleValues((upVotes, comments) => { Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments."); }); 

Solo use en modo OOP una clase como esta:

 class div { public int remainder; public int quotient(int dividend, int divisor) { remainder = ...; return ...; } } 

El miembro de la función devuelve el cociente en el que la mayoría de las personas que llaman están principalmente interesadas. Además, almacena el rest como un miembro de datos, al que puede acceder fácilmente la persona que llama después.

De esta forma puede tener muchos “valores de retorno” adicionales, muy útiles si implementa llamadas de base de datos o de red, donde pueden necesitarse muchos mensajes de error, pero solo en caso de que ocurra un error.

Ingresé esta solución también en la pregunta de C ++ a la que se refiere OP.

De este artículo, puedes usar tres opciones como dicen las publicaciones anteriores.

KeyValuePair es la forma más rápida.

está en el segundo.

Tuple es el más lento.

De todos modos, esto depende de lo que sea mejor para su escenario.

Podría usar un objeto dynamic. Creo que tiene una mejor legibilidad que Tuple.

 static void Main(string[] args){ var obj = GetMultipleValues(); Console.WriteLine(obj.Id); Console.WriteLine(obj.Name); } private static dynamic GetMultipleValues() { dynamic temp = new System.Dynamic.ExpandoObject(); temp.Id = 123; temp.Name = "Lorem Ipsum"; return temp; } 

La versión futura de C # incluirá tuplas con nombre. Eche un vistazo a esta sesión de channel9 para la demostración https://channel9.msdn.com/Events/Build/2016/B889

Salte a las 13:00 para las cosas de la tupla. Esto permitirá cosas como:

 (int sum, int count) Tally(IEnumerable list) { // calculate stuff here return (0,0) } int resultsum = Tally(numbers).sum 

(ejemplo incompleto del video)

puedes intentar esto

 public IEnumerable Get() { return new string[] { "value1", "value2" }; } 

Formas de hacerlo:

1) KeyValuePair (Mejor rendimiento – 0.32 ns):

  KeyValuePair Location(int p_1, int p_2, int p_3, int p_4) { return new KeyValuePair(p_2 - p_1, p_4-p_3); } 

2) Tuple – 5.40 ns:

  Tuple Location(int p_1, int p_2, int p_3, int p_4) { return new Tuple(p_2 - p_1, p_4-p_3); } 

3) fuera (1.64 ns) o ref 4) Cree su propia clase / estructura personalizada

ns -> nanosegundos

Referencia: valores de retorno múltiple .

También puede usar un resultado de operación

 public OperationResult DoesSomething(int number1, int number2) { // Your Code var returnValue1 = "return Value 1"; var returnValue2 = "return Value 2"; var operationResult = new OperationResult(returnValue1, returnValue2); return operationResult; }