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


Answers

Ahora que C # 7 ha lanzado, puedes usar la nueva sintaxis de 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 :)

Question

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

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




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



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 pila. 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 codificación 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.




puedes probar este "KeyValuePair"

private KeyValuePair<int, int> GetNumbers()
{
  return new KeyValuePair<int, int>(1, 2);
}


var numbers = GetNumbers();

Console.WriteLine("Output : {0}, {1}",numbers.Key, numbers.Value);

Salida:

Salida: 1, 2




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 pila 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 compilador. 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.




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 pila 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<T>

Ejemplo de Tuple:

Devolución de valores múltiples de DataType con Tuple<T>

using System;

class Program
{
    static void Main()
    {
    // Create four-item tuple; use var implicit type.
    var tuple = new Tuple<string, string[], int, int[]>("perl",
        new string[] { "java", "c#" },
        1,
        new int[] { 2, 3 });
    // Pass tuple as argument.
    M(tuple);
    }

    static void M(Tuple<string, string[], int, int[]> 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 .




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



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



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 dinámicos y funcionales mediante tuplas, pero no en C #.




puedes intentar esto

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



Podría usar un objeto dinámico. 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;
}



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 resto 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.