Возврат нескольких значений вызывающему методу - PullRequest
358 голосов
/ 14 апреля 2009

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

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

Ответы [ 26 ]

550 голосов
/ 23 апреля 2012

Использование .NET 4.0 + кортеж :

Например:

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

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

290 голосов
/ 05 апреля 2016

Теперь, когда C # 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

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

157 голосов
/ 04 июня 2015

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

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. Кортеж

Класс кортежа

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

C # 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);
}
74 голосов
/ 14 апреля 2009

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

Использование параметра 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; }
}
38 голосов
/ 14 апреля 2009

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

public void Foo(int input, out int output1, out string output2, out string errors) {
    // set out parameters inside function
}
33 голосов
/ 14 апреля 2009

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

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

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

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

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

19 голосов
/ 14 апреля 2009

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

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
11 голосов
/ 14 апреля 2009

Есть несколько способов сделать это. Вы можете использовать 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) { }

Этот последний подход проще и легче для чтения и понимания.

11 голосов
/ 14 апреля 2009

Нет, вы не можете вернуть несколько значений из функции в C # (для версий ниже C # 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';
}
10 голосов
/ 14 апреля 2009

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

Между тем, есть два варианта.

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

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

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

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

...