Возвращает несколько значений вызывающему методу
Вопрос
Я прочитал Версия этого вопроса на C ++ но на самом деле не понимал этого.
Может кто-нибудь, пожалуйста, четко объяснить, можно ли это сделать и как?
Решение
Использование Кортеж .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:
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);
}
Вы не можете сделать это на C #.Что вы можете сделать, так это иметь 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; }
}
Если вы имеете в виду возврат нескольких значений, вы можете либо вернуть класс / структуру, содержащую значения, которые вы хотите вернуть, либо использовать ключевое слово "out" для ваших параметров, например:
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
Предыдущий плакат правильный.Вы не можете возвращать несколько значений из метода C #.Тем не менее, у вас есть пара вариантов:
- Возвращает структуру, содержащую несколько элементов
- Возвращает экземпляр класса
- Использовать выходные параметры (используя вон или ссылка ключевые слова)
- Используйте словарь или пару ключ-значение в качестве выходных данных
Плюсы и минусы здесь часто трудно оценить.Если вы возвращаете структуру, убедитесь, что она небольшая, потому что структуры имеют тип значения и передаются в стеке.Если вы возвращаете экземпляр класса, здесь есть некоторые шаблоны проектирования, которые вы, возможно, захотите использовать, чтобы избежать проблем - члены классов могут быть изменены, потому что 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
параметр идентичен a ref
параметр с дополнительным правилом, применяемым компилятором.Это правило заключается в том, что если вы передаете out
параметр в функцию, эта функция должна установить его значение перед возвратом.Помимо этого правила, out
параметр работает точно так же, как ref
параметр.
Окончательный подход (и лучший в большинстве случаев) заключается в создании типа, который инкапсулирует оба значения и позволяет функции возвращать это:
class FooBar
{
public int i { get; set; }
public Bar b { get; set; }
}
FooBar Foo(Bar bar) { }
Этот окончательный подход проще и понятнее для чтения.
Нет, вы не можете возвращать несколько значений из функции в 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 # 4 вы сможете использовать встроенную поддержку кортежей, чтобы легко справиться с этим.
В то же время, есть два варианта.
Во-первых, вы можете использовать параметры ref или out для присвоения значений вашим параметрам, которые передаются обратно вызывающей процедуре.
Это выглядит как:
void myFunction(ref int setMe, out int youMustSetMe);
Во-вторых, вы можете обернуть возвращаемые значения в структуру или класс и передать их обратно как члены этой структуры.KeyValuePair хорошо работает для 2 - для более чем 2 вам понадобится пользовательский класс или структура.
В C # 7 появился новый Tuple
синтаксис:
static (string foo, int bar) GetTuple()
{
return ("hello", 5);
}
Вы можете вернуть это как запись:
var result = GetTuple();
var foo = result.foo
// foo == "hello"
Вы также можете использовать новый синтаксис deconstructor:
(string foo) = GetTuple();
// foo == "hello"
Однако будьте осторожны с сериализацией, все это синтаксический сахар - в реальном скомпилированном коде это будет Tupel<string, int>
(как согласно принятому ответу) с Item1
и Item2
вместо того , чтобы foo
и bar
.Это означает, что при сериализации (или десериализации) вместо этого будут использоваться эти имена свойств.
Итак, для сериализации объявите класс записи и верните его вместо этого.
Также новым в C # 7 является улучшенный синтаксис для out
параметры.Теперь вы можете объявить out
встроенный, который лучше подходит в некоторых контекстах:
if(int.TryParse("123", out int result)) {
// Do something with result
}
Однако в основном вы будете использовать это в .Собственных библиотеках NET, а не в ваших собственных функциях.
Некоторые ответы предполагают использование исходящие параметры но я рекомендую не использовать это из-за они не работают с асинхронными методами.Видишь это для получения дополнительной информации.
В других ответах указывалось использование Tuple, которое я бы тоже рекомендовал, но с использованием новой функции, представленной в 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}.");
Более подробную информацию можно найти здесь.
вы можете попробовать эту "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
Классы, Структуры, Коллекции и массивы могут содержать несколько значений.Выходные и опорные параметры также могут быть заданы в функции.Возвращать несколько значений возможно в динамических и функциональных языках с помощью кортежей, но не в C #.
В основном существуют два метода.1.Используйте параметры out / ref 2.Возвращает массив объектов
Вот основные Two
методы:
1) Использование 'out
' в качестве параметра
Вы также можете использовать 'out' как для 4.0, так и для младших версий.
Пример "выхода":
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
ПРИМЕЧАНИЕ: Использование Tuple допустимо начиная с 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.
От это статья, вы можете использовать три варианта, как говорилось в постах выше.
Ключевая пара значений это самый быстрый способ.
вон находится на втором.
Кортеж является самым медленным.
В любом случае, это зависит от того, что лучше всего подходит для вашего сценария.
Будущая версия 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
(неполный пример из видео)
Вы могли бы использовать динамический объект.Я думаю, что у него лучшая читабельность, чем у Кортежа.
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;
}
<--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);
Я надеюсь, что это сработает.
Способы сделать это:
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) Кортеж - 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 ns) или ссылка 4) Создайте свой собственный пользовательский класс / структуру
ns -> наносекунды
Ссылка: множественные возвращаемые значения.
вы можете попробовать это
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;
}
Есть много способов;но если вы не хотите создавать новый объект или структуру или что-то подобное, вы можете сделать, как показано ниже, после C # 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");
}
Сегодня программистам нужно время и непростительные методы.Простое, работающее и быстрое решение:
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];