Как я могу вернуть несколько значений из функции в C#?
прочитал C++ версия этого вопроса но на самом деле не понимал этого.
может кто-нибудь, пожалуйста, объяснить ясно, если это можно сделать и как?
25 ответов
использовать .Net версии 4.0+'кортеж с:
Например:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
кортежи с двумя значениями имеют Item1
и Item2
свойства.
теперь, когда c# 7 был выпущен, вы можете использовать новый синтаксис включенных кортежей
(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
проверить этой ссылке чтобы увидеть больше примеров того, что можно сделать :)
вы можете использовать три разных способа
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 / class
использование 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;
}
использование класса:
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. Кортеж!--10-->
Кортеж класс!--10-->
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);
}
вы не можете сделать это в C#. Что вы можете сделать, это иметь out
parameter или верните свой собственный класс (или struct, если вы хотите, чтобы он был неизменяемым).
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; }
}
Если вы имеете в виду возврат нескольких значений, вы можете либо вернуть класс/структуру, содержащую значения, которые вы хотите вернуть, либо использовать ключевое слово "out" для ваших параметров, например:
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
предыдущий постер прав. Невозможно вернуть несколько значений из метода C#. Тем не менее, у вас есть несколько вариантов:
- возвращает структуру, содержащую несколько элементов
- возврат экземпляра класса
- использовать выходные параметры (с помощью out или ref ключевые слова)
- используйте словарь или пару ключ-значение в качестве вывода
плюсы и минусы здесь часто трудно выяснить. Если вы возвращаете структуру, убедитесь, что она небольшая, потому что структуры являются типом значения и передаются в стек. Если вы возвращаете экземпляр класса, здесь есть некоторые шаблоны проектирования, которые вы можете использовать, чтобы избежать проблем - члены классов могут быть изменены, потому что C# передает объекты по ссылке (у вас нет ByVal, как вы сделали в VB).
наконец, вы можете использовать выходные параметры, но я бы ограничил использование этого сценариями, когда у вас есть только пара (например, 3 или менее) параметры-в противном случае все становится уродливым и трудно поддерживать. Кроме того, использование выходных параметров может быть ингибитором гибкости, потому что ваша подпись метода должна будет меняться каждый раз, когда вам нужно добавить что-то к возвращаемому значению, тогда как возвращая экземпляр структуры или класса, вы можете добавлять члены без изменения подписи метода.
с архитектурной точки зрения я бы порекомендовал не использовать пары ключ-значение или словари. Я считаю, что этот стиль кодирования требует " секрет знание " в коде, который потребляет метод. Он должен заранее знать, какие ключи будут и что означают значения, и если разработчик, работающий над внутренней реализацией, изменит способ создания словаря или KVP, он может легко создать каскад сбоев во всем приложении.
вы либо вернуть экземпляр класса или использовать из параметры. Вот пример параметров:
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
есть несколько способов сделать это. Вы можете использовать ref
параметры:
int Foo(ref Bar bar) { }
при этом передается ссылка на функцию, тем самым позволяя функции изменять объект в стеке вызывающего кода. Хотя это технически не "возвращаемое" значение, это способ заставить функцию делать что-то подобное. В коде выше функция будет возвращать int
и (потенциально) изменить bar
.
другой аналогичный подход заключается в использовании out
параметр. Ан out
параметр идентичен параметру ref
параметр с дополнительным, принудительным правилом компилятора. Это правило заключается в том, что если вы передадите out
параметр в функцию, эта функция должна установить свое значение до возвращения. Кроме этого правила, an
В C# 4, Вы сможете использовать встроенную поддержку для кортежей, чтобы легко справиться с этим.
тем временем, есть два варианта.
во-первых, вы можете использовать ref или out-параметры для присвоения значений параметров, которые возвращаются в вызывающую программу.
Это выглядит так:
void myFunction(ref int setMe, out int youMustSetMe);
во-вторых, вы можете обернуть возвращаемые значения в структуру или класс и передать их обратно как члены этой структуры. KeyValuePair работает хорошо для 2-для более чем 2 вам понадобится пользовательский класс или структура.
нет, вы не можете возвращать несколько значений из функции в C# (для версий ниже C# 7), по крайней мере, не так, как вы можете это сделать в Python.
тем не менее, есть несколько альтернатив:
вы можете вернуть массив типа object с несколькими значениями, которые вы хотите в нем.
private object[] DoSomething()
{
return new [] { 'value1', 'value2', 3 };
}
можно использовать out
параметры.
private string DoSomething(out string outparam1, out int outparam2)
{
outparam1 = 'value2';
outparam2 = 3;
return 'value1';
}
В C#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>
(as за принятый ответ) С Item1
и Item2
вместо foo
и bar
. Это означает, что сериализация (или десериализация) вместо этого будут использоваться эти имена свойств.
Итак, для сериализации объявите класс записи и верните его вместо этого.
также новым в C#7 является улучшенный синтаксис для out
параметры. Теперь вы можете объявить out
inline, который лучше подходит в некоторых контекстах:
if(int.TryParse("123", out int result)) {
// Do something with result
}
однако в основном вы будете использовать это в собственных библиотеках .NET, а не в собственных функциях.
вы можете попробовать этот "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
некоторые из этих ответов указано, что использовать out параметр но я рекомендую не использовать это из-за они не работают с async-методов. Видеть этой для получения дополнительной информации.
другие ответы, указанные с помощью кортежа, который я бы тоже рекомендовал, но используя новую функцию, представленную в 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}.");
дополнительная информация здесь.
классы, структуры, коллекции и массивы могут содержать несколько значений. Выходные и опорные параметры также могут быть установлены в функции. Возврат нескольких значений возможен в динамических и функциональных языках с помощью кортежей, но не в C#.
вот основные Two
методы:
1) Использование 'out
в качестве параметра
Вы можете использовать " 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
-ключевое слово описывает параметры, фактические местоположения переменных скопировано в стек вызываемого метода, где эти же расположения могут быть переписаны. Это означает, что вызывающий метод получит доступ к измененному параметру.
2) Tuple<T>
пример кортежа:
возврат нескольких значений типа данных с помощью 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);
}
}
}
выход
perl
java
c#
1
2
3
Примечание: использование кортежа допустимо из Framework 4.0 и выше.Tuple
тип class
. Он будет выделен в отдельном расположении на управляемой куче в памяти. После создания Tuple
, вы не можете изменить значения его fields
. Это делает Tuple
еще как struct
.
метод, принимающий делегат, может предоставить вызывающему несколько значений. Это заимствует из моего ответа здесь и использует немного из принятый ответ Хадаса.
delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
callback(1, 2);
}
вызывающие объекты предоставляют лямбда (или именованную функцию), а intellisense помогает, копируя имена переменных из делегата.
GetMultipleValues((upVotes, comments) =>
{
Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
просто используйте в ООП-манере такой класс:
class div
{
public int remainder;
public int quotient(int dividend, int divisor)
{
remainder = ...;
return ...;
}
}
член функции возвращает фактор, который интересует большинство вызывающих абонентов. Кроме того, он сохраняет остаток в качестве члена данных, который легко доступен вызывающему абоненту впоследствии.
таким образом, у вас может быть много дополнительных "возвращаемых значений", очень полезных при реализации вызовов базы данных или сети, где может потребоваться много сообщений об ошибках, но только в случае ошибки происходит.
Я ввел это решение также В вопрос C++, на который ссылается OP.
с этой статья, вы можете использовать три варианта, как указано выше.
KeyValuePair самый быстрый путь.
из на втором.
кортежа!--6--> самая медленная.
в любом случае, это зависит от того, что лучше для вашего сценария.
вы можете использовать динамический объект. Я думаю, что он имеет лучшую читаемость, чем Кортеж.
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;
}
способы сделать это:
1) KeyValuePair (самое лучшее представление-0.32 ns):
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) Кортеж - 5.40 НС:
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) из (1.64 НС) или Реф 4) Создайте свой собственный класс/структуру struct
НС -> НС
ссылки: несколько возвращаемых значений.
будущая версия C# будет включать именованные кортежи. Посмотрите на эту сессию channel9 для демонстрации 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
(неполный пример из видео)
вы можете попробовать это
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
вы также можете использовать 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;
}
сегодня, программистам нужно время и методы unforgotable. Простое, рабочее и быстрое решение:
private int[] SumAndSub(int A, int B)
{
return new[] { A + B , A - B };
}
используя его где-то;
int sum = SumAndSub(20, 5)[0];
int sub = SumAndSub(20, 5)[1];