Возврат нескольких значений вызывающему методу

Я прочитал версию С++ этого вопроса, но на самом деле не понял.

Может кто-нибудь объяснить, ясно ли это, и как?

Ответ 1

Используйте .NET 4. 0+ Tuple:

Например:

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

Кортежи с двумя значениями имеют Item1 и Item2 качестве свойств.

Ответ 2

Теперь, когда С# 7 выпущен, вы можете использовать новый включенный синтаксис Tuples

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

Вы также можете предоставить имена своим элементам (чтобы они не были "Item1", "Item2" и т.д.). Вы можете сделать это, добавив имя в подпись или методы возврата:

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

или же

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

Их также можно деконструировать, что является довольно приятной новой функцией:

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

Проверьте эту ссылку, чтобы увидеть больше примеров того, что можно сделать :)

Ответ 3

Вы можете использовать три разных способа

1. параметры ref/out

используя 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;
}

используя:

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. структура/класс

используя структуру:

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

используя класс:

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

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<int, int> Add_Multiply(int a, int b)
{
    var tuple = new Tuple<int, int>(a + b, a * b);
    return tuple;
}

С# 7 кортежей

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

Ответ 4

Вы не можете сделать это на С#. Что вы можете сделать, это иметь параметр out или вернуть свой собственный класс (или структуру, если вы хотите, чтобы он был неизменным).

Использование параметра
public int GetDay(DateTime date, out string name)
{
  // ...
}
Использование пользовательского класса (или структуры)
public DayOfWeek GetDay(DateTime date)
{
  // ...
}

public class DayOfWeek
{
  public int Day { get; set; }
  public string Name { get; set; }
}

Ответ 5

Если вы имеете в виду возврат нескольких значений, вы можете либо вернуть класс /struct, содержащий значения, которые хотите вернуть, либо использовать ключевое слово "out" для своих параметров, например:

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

Ответ 6

Предыдущий плакат прав. Вы не можете вернуть несколько значений из метода С#. Однако у вас есть несколько вариантов:

  • Возвращает структуру, содержащую несколько элементов
  • Возвращает экземпляр класса
  • Используйте выходные параметры (используя ключевые слова out или ref)
  • Используйте словарь или пару ключ-значение в качестве вывода

Достоинства и недостатки здесь часто трудно понять. Если вы вернете структуру, убедитесь, что она маленькая, потому что structs - тип значения и передается в стек. Если вы возвращаете экземпляр класса, здесь есть некоторые шаблоны проектирования, которые вы можете использовать, чтобы избежать возникновения проблем - члены классов могут быть изменены, поскольку С# передает объекты по ссылке (у вас нет ByVal, как вы это делали в VB).

Наконец, вы можете использовать выходные параметры, но я бы ограничил использование этого сценариями, когда у вас есть пара (например, 3 или меньше) параметров - в противном случае все становится уродливо и сложно поддерживать. Кроме того, использование выходных параметров может быть ингибитором гибкости, потому что ваша сигнатура метода должна будет меняться каждый раз, когда вам нужно что-то добавить к возвращаемому значению, а при возврате экземпляра структуры или класса вы можете добавлять элементы без изменения сигнатуры метода.

С архитектурной точки зрения я бы рекомендовал не использовать пары ключ-значение или словари. Я считаю, что этот стиль кодирования требует "секретного знания" в коде, который использует этот метод. Он должен заранее знать, какими будут ключи и что означают значения, и если разработчик, работающий над внутренней реализацией, меняет способ создания словаря или KVP, он может легко создать каскад сбоев во всем приложении.

Ответ 7

Вы либо возвращаете экземпляр класса, либо используете параметры. Вот пример выходных параметров:

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

Назовите это так:

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

Ответ 8

Нет, вы не можете возвращать несколько значений из функции в С# (для версий ниже С# 7), по крайней мере, не так, как вы можете сделать это на Python.

Однако есть несколько альтернатив:

Вы можете вернуть массив объекта типа с несколькими значениями, которые вы хотите в нем.

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

Вы можете использовать параметры out.

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

Ответ 9

Есть несколько способов сделать это. Вы можете использовать параметры ref:

int Foo(ref Bar bar) { }

Это передает ссылку на функцию, тем самым позволяя функции изменять объект в стеке вызывающего кода. Хотя это технически не "возвращаемое" значение, это способ сделать что-то подобное. В вышеприведенном коде функция возвращает int и (возможно) изменение bar.

Другой аналогичный подход заключается в использовании параметра out. Параметр out идентичен параметру ref с дополнительным принудительным правилом компилятора. Это правило состоит в том, что если вы передаете параметр out в функцию, эта функция должна установить его значение перед возвратом. Помимо этого правила параметр out работает так же, как параметр ref.

Конечный подход (и лучший в большинстве случаев) заключается в создании типа, который инкапсулирует оба значения и позволяет функции возвращать это:

class FooBar 
{
    public int i { get; set; }
    public Bar b { get; set; }
}

FooBar Foo(Bar bar) { }

Этот окончательный подход проще и легче читать и понимать.

Ответ 10

В С# 4 вы сможете использовать встроенную поддержку кортежей, чтобы справиться с этим легко.

В то же время есть два варианта.

Во-первых, вы можете использовать параметры ref или out для назначения значений вашим параметрам, которые передаются обратно вызывающей процедуре.

Это выглядит так:

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

Во-вторых, вы можете обернуть ваши возвращаемые значения в структуру или класс и передать их как члены этой структуры. KeyValuePair отлично работает для 2 - для более чем 2 вам нужен пользовательский класс или структура.

Ответ 11

  В некоторых ответах предлагается использовать параметры, но я рекомендую не использовать это из-за они не работают с асинхронными методами. Видеть это для получения дополнительной информации.

Другие ответы приведены с использованием Tuple, который я бы тоже рекомендовал, но с использованием новой функции, представленной в С# 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}.");

Дополнительную информацию можно найти здесь.

Ответ 12

В С# 7 Существует новый синтаксис Tuple:

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

Вы можете вернуть это как запись:

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

Вы также можете использовать новый синтаксис деконструктора:

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

Будьте осторожны с сериализацией, но все это синтаксический сахар - в самом компилированном коде это будет Tupel<string, int> (как за принятый ответ) с Item1 и Item2 вместо foo и bar. Это означает, что сериализация (или десериализация) будет использовать эти имена свойств.

Итак, для сериализации объявляем класс записи и возвращаем это вместо.

Также новый в С# 7 является улучшенным синтаксисом для параметров out. Теперь вы можете объявить встроенную строку out, которая лучше подходит для некоторых контекстов:

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

Однако, в основном вы будете использовать это в собственных библиотеках .NET, а не в своих собственных функциях.

Ответ 13

вы можете попробовать этот "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);

Выход:

Выход: 1, 2

Ответ 14

Классы, структуры, коллекции и массивы могут содержать несколько значений. Выходные и опорные параметры также могут быть установлены в функции. Возвращение нескольких значений возможно в динамическом и функциональном языках с помощью кортежей, но не в С#.

Ответ 15

В основном существуют два метода. 1. Использовать параметры /ref 2. Верните массив объектов

Ответ 16

Вот основные методы Two:

1) Использование 'out' в качестве параметра Вы можете использовать "выход" для версий 4.0 и второстепенных версий.

Пример "out":

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

Вывод:

Область прямоугольника - 20

Периметр прямоугольника равен 18

* Примечание: * out -keyword описывает параметры, фактические местоположения переменных которых скопированы в стек вызываемого метода, где те же самые местоположения могут быть переписаны. Это означает, что вызывающий метод будет обращаться к измененному параметру.

2) Tuple<T>

Пример набора:

Возврат нескольких значений DataType с помощью 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 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);
    }
    }
}

Выход

perl
java
c#
1
2
3

ПРИМЕЧАНИЕ. Использование кортежа действительно из Framework 4.0 и выше. Tuple type - это class. Он будет выделен в отдельном месте на управляемой куче в памяти. Создав Tuple, вы не сможете изменить значения его fields. Это делает Tuple больше похожим на struct.

Ответ 17

Метод, принимающий делегат, может предоставить несколько значений вызывающему. Это берет из моего ответа здесь и немного использует принятый Hadas ответ.

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

Абоненты предоставляют lambda (или именованную функцию), а intellisense помогает, копируя имена переменных из делегата.

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

Ответ 18

Есть много способов; но если вы не хотите создавать новый объект или структуру или что-то подобное, вы можете сделать это, как показано ниже, после С# 7.0 :

 (string firstName, string lastName) GetName(string myParameter)
    {
        var firstName = myParameter;
        var lastName = myParameter + " something";
        return (firstName, lastName);
    }

    void DoSomethingWithNames()
    {
        var (firstName, lastName) = GetName("myname");

    }

Ответ 19

Просто используйте в ООП класс вроде этого:

class div
{
    public int remainder;

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

Член функции возвращает частное, к которому в основном обращаются большинство вызывающих. Кроме того, он сохраняет остаток в качестве члена данных, который впоследствии легко доступен вызывающему.

Таким образом, у вас может быть много дополнительных "возвращаемых значений", очень полезно, если вы реализуете базы данных или сетевые вызовы, где может понадобиться много сообщений об ошибках, но только в случае возникновения ошибки.

Я ввел это решение также в вопрос С++, на который ссылается OP.

Ответ 20

Из этой статьи вы можете использовать три варианта в качестве сообщений выше.

KeyValuePair - самый быстрый способ.

out находится на втором.

Кортеж является самым медленным.

В любом случае, это зависит от того, что лучше для вашего сценария.

Ответ 21

Можно использовать динамический объект. Я думаю, что он имеет лучшую читаемость, чем 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;
}

Ответ 22

Будущая версия С# будет содержать именованные кортежи. Взгляните на этот сеанс канала9 для демонстрации https://channel9.msdn.com/Events/Build/2016/B889

Пропустить до 13:00 для кортежа. Это позволит использовать такие вещи, как:

(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}

int resultsum = Tally(numbers).sum

(неполный пример из видео)

Ответ 23

<--Return more statements like this you can --> 

public (int,string,etc) Sample( int a, int b)  
{
    //your code;
    return (a,b);  
}

Вы можете получить код как

(c,d,etc) = Sample( 1,2);

Надеюсь это работает.

Ответ 24

Способы сделать это:

1) KeyValuePair (лучшая производительность - 0,32 нс):

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

2) Tuple - 5.40 ns:

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

3) out (1.64 нс) или ref 4) Создайте свой собственный класс /struct

ns → наносекунды

Ссылка: multiple-return-values.

Ответ 25

вы можете попробовать это

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

Ответ 26

Вы также можете использовать OperationResult

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

Ответ 27

Сегодня программистам нужно время и незабываемые методы. Простое, рабочее и быстрое решение:

private int[] SumAndSub(int A, int B)
{
    return new[] { A + B , A - B };
}

Используя это где-то;

var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[0];