Я прочитав версію цього питання на C ++, але насправді не зрозумів.
Чи може хтось, будь ласка, пояснити чітко, чи можна це зробити і як?
Я прочитав версію цього питання на C ++, але насправді не зрозумів.
Чи може хтось, будь ласка, пояснити чітко, чи можна це зробити і як?
Відповіді:
В C # 7 і вище дивіться цю відповідь .
У попередніх версіях ви можете використовувати .NET 4.0 + 's Tuple :
Наприклад:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
Кортежі з двома значеннями мають Item1
і Item2
як властивості.
public (int sum, int count) GetMultipleValues() { return (1, 2); }
Цей приклад взятий з нашого прикладу теми Документація щодо цього .
Тепер, коли 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
Перегляньте це посилання, щоб побачити більше прикладів того, що можна зробити :)
Можна скористатися трьома різними способами
1. параметри відмови / виходу
використовуючи посилання:
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; }
}
async
методів. Tuple
це шлях. ( out
Хоча я використовую параметри в синхронних операціях; вони дійсно корисні в тих випадках.)
Якщо ви маєте на увазі повернення декількох значень, ви можете або повернути клас / структуру, що містить значення, які ви хочете повернути, або використовувати ключове слово "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, він може легко створити каскад відмов у всій програмі.
Exception
якщо друге значення, яке ви хочете повернути, є невідмінним від першого: наприклад, коли ви хочете повернути або якесь вдале значення, або вид невдалого значення.
Ви або повертає екземпляр класу або використовувати з параметрів. Ось приклад вихідних параметрів:
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
Є багато способів; але якщо ви не хочете створювати новий об’єкт чи структуру чи щось подібне, ви можете зробити, як нижче, після 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");
}
У 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"
Однак будьте обережні з серіалізацією, все це синтаксичний цукор - у фактично складеному коді це буде Tuple<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}.");
Додаткову інформацію можна знайти тут .
Існує кілька способів зробити це. Ви можете використовувати 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) { }
Цей підсумковий підхід простіший і легший для читання та розуміння.
Ні, ви не можете повернути кілька значень з функції в 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';
}
У C # 4 ви зможете використовувати вбудовану підтримку кортежів, щоб легко впоратися з цим.
Тим часом є два варіанти.
По-перше, ви можете використовувати параметри ref або out для присвоєння значень вашим параметрам, які передаються назад у процедуру виклику.
Це виглядає так:
void myFunction(ref int setMe, out int youMustSetMe);
По-друге, ви можете згорнути свої повернені значення в структуру або клас і передати їх назад членам цієї структури. KeyValuePair добре працює для 2 - для більш ніж 2 вам знадобиться спеціальний клас або структура.
ви можете спробувати цей "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 #.
Ось основні 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>
Приклад кортежу:
Повернення кількох значень 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'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.");
});
Просто використовуйте такий спосіб, як OOP:
class div
{
public int remainder;
public int quotient(int dividend, int divisor)
{
remainder = ...;
return ...;
}
}
Член функції повертає той коефіцієнт, який цікавить в основному більшість абонентів. Крім того, він зберігає залишок як член даних, який згодом легко стає доступним.
Таким чином, у вас може бути багато додаткових "повернутих значень", дуже корисних, якщо ви реалізуєте дзвінки до бази даних або мережеві дзвінки, де може знадобитися багато повідомлень про помилки, але лише у випадку помилки.
Я ввів це рішення також у питанні C ++, на яке посилається ОП.
Майбутня версія C # включає в себе названі кортежі. Погляньте на цей сеанс 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
(неповний приклад із відео)
Ви можете використовувати динамічний об’єкт. Я думаю, він має кращу читабельність, ніж 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;
}
Способи зробити це:
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) out (1,64 нс) або ref 4) Створіть свій власний клас / структура
ns -> наносекунд
Довідка: множинні значення повернення .
ви можете спробувати це
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
, щоб не довелося явно створювати нове string[]
?
Ви також можете використовувати 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;
}
Швидкий відповідь, спеціально для типу масиву, повертає:
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[1];