Przeczytałem wersję tego pytania w C ++, ale tak naprawdę jej nie rozumiałem.
Czy ktoś może jasno wyjaśnić, czy można to zrobić i jak?
Przeczytałem wersję tego pytania w C ++, ale tak naprawdę jej nie rozumiałem.
Czy ktoś może jasno wyjaśnić, czy można to zrobić i jak?
Odpowiedzi:
W C # 7 i powyżej zobacz tę odpowiedź .
W poprzednich wersjach można używać Tuple .NET 4.0 + :
Na przykład:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
Krotki z dwiema wartościami mają Item1
i Item2
jako właściwości.
public (int sum, int count) GetMultipleValues() { return (1, 2); }
Ten przykład został zaczerpnięty z naszego przykładu tematu Dokumentacja na ten temat .
Teraz, gdy C # 7 zostało wydane, możesz używać nowej dołączonej składni Tuples
(string, string, string) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
które można następnie wykorzystać w następujący sposób:
var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");
Możesz także nadać nazwy swoim elementom (więc nie są to „Item1”, „Item2” itp.). Możesz to zrobić, dodając nazwę do podpisu lub metody zwrotu:
(string first, string middle, string last) LookupName(long id) // tuple elements have names
lub
return (first: first, middle: middle, last: last); // named tuple elements in a literal
Można je również zdekonstruować, co jest całkiem fajną nową funkcją:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
Sprawdź ten link, aby zobaczyć więcej przykładów tego, co można zrobić :)
Możesz użyć trzech różnych sposobów
1. parametry ref / out
przy użyciu 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;
}
używając:
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
przy użyciu 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;
}
za pomocą klasy:
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
Klasa 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;
}
C # 7 krotek
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);
}
Nie możesz tego zrobić w C #. Możesz mieć out
parametr lub zwrócić własną klasę (lub struct, jeśli chcesz, aby była niezmienna).
public int GetDay(DateTime date, out string name)
{
// ...
}
Używanie niestandardowej klasy (lub struktury)
public DayOfWeek GetDay(DateTime date)
{
// ...
}
public class DayOfWeek
{
public int Day { get; set; }
public string Name { get; set; }
}
async
metod. Tuple
jest droga. (Używam jednak out
parametrów w operacjach synchronicznych; w takich przypadkach są one rzeczywiście przydatne.)
Jeśli masz na myśli zwracanie wielu wartości, możesz albo zwrócić klasę / strukturę zawierającą wartości, które chcesz zwrócić, albo użyć słowa kluczowego „out” w parametrach, na przykład:
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
Poprzedni plakat ma rację. Nie można zwrócić wielu wartości z metody C #. Masz jednak kilka opcji:
Tutaj zalety i wady są często trudne do zrozumienia. Jeśli zwracasz strukturę, upewnij się, że jest mała, ponieważ struktury są typu wartości i są przekazywane na stos. Jeśli zwracasz instancję klasy, możesz tutaj zastosować pewne wzorce projektowe, aby uniknąć problemów - członkowie klas mogą być modyfikowani, ponieważ C # przekazuje obiekty przez referencję (nie masz ByVal jak w VB ).
Wreszcie możesz użyć parametrów wyjściowych, ale ograniczyłbym użycie tego do scenariuszy, gdy masz tylko kilka (jak 3 lub mniej) parametrów - w przeciwnym razie rzeczy stają się brzydkie i trudne do utrzymania. Ponadto użycie parametrów wyjściowych może hamować sprawność, ponieważ sygnatura metody będzie musiała się zmieniać za każdym razem, gdy trzeba będzie coś dodać do wartości zwracanej, a zwracając instancję struktury lub klasy można dodawać elementy bez modyfikowania sygnatury metody.
Z architektonicznego punktu widzenia odradzałbym używanie par klucz-wartość lub słowników. Uważam, że ten styl kodowania wymaga „tajnej wiedzy” w kodzie używającym metody. Musi z góry wiedzieć, jakie będą klucze i co oznaczają wartości, a jeśli programista pracujący nad wewnętrzną implementacją zmieni sposób tworzenia słownika lub KVP, może łatwo stworzyć kaskadę awarii w całej aplikacji.
Exception
jeśli druga wartość, którą chcesz zwrócić, jest rozłączna od pierwszej: na przykład, gdy chcesz zwrócić albo wartość udaną, albo rodzaj wartości nieudanej.
Albo zwraca instancję klasy lub skorzystać z parametrów. Oto przykład naszych parametrów:
void mymethod(out int param1, out int param2)
{
param1 = 10;
param2 = 20;
}
Nazwij to tak:
int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10
Jest wiele sposobów; ale jeśli nie chcesz tworzyć nowego obiektu lub struktury lub czegoś takiego, możesz to zrobić jak poniżej po 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");
}
W C # 7 dostępna jest nowa Tuple
składnia:
static (string foo, int bar) GetTuple()
{
return ("hello", 5);
}
Możesz zwrócić to jako zapis:
var result = GetTuple();
var foo = result.foo
// foo == "hello"
Możesz także użyć nowej składni dekonstruktora:
(string foo) = GetTuple();
// foo == "hello"
Uważaj jednak na serializację, wszystko to jest cukier składniowy - w faktycznie skompilowanym kodzie będzie to Tuple<string, int>
(zgodnie z przyjętą odpowiedzią ) zi Item1
oraz Item2
zamiast foo
i bar
. Oznacza to, że serializacja (lub deserializacja) użyje zamiast tego tych nazw właściwości.
W celu serializacji zadeklaruj klasę rekordów i zwróć ją.
Nowością w C # 7 jest ulepszona składnia out
parametrów. Możesz teraz zadeklarować out
wstawienie, które lepiej pasuje w niektórych kontekstach:
if(int.TryParse("123", out int result)) {
// Do something with result
}
Jednak przeważnie będziesz tego używał we własnych bibliotekach .NET, a nie we własnych funkcjach.
Niektóre odpowiedzi sugerują użycie parametrów out, ale nie polecam tego, ponieważ nie działają one z metodami asynchronicznymi . Zobacz to, aby uzyskać więcej informacji.
Inne odpowiedzi podano przy użyciu Tuple, które również poleciłbym, ale przy użyciu nowej funkcji wprowadzonej w 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}.");
Więcej informacji można znaleźć tutaj .
Można to zrobić na kilka sposobów. Możesz użyć ref
parametrów:
int Foo(ref Bar bar) { }
To przekazuje odwołanie do funkcji, umożliwiając w ten sposób modyfikacji obiektu na stosie kodu wywołującego. Chociaż technicznie nie jest to wartość „zwrócona”, jest to sposób, aby funkcja zrobiła coś podobnego. W powyższym kodzie funkcja zwróci int
i (potencjalnie) zmodyfikuje bar
.
Innym podobnym podejściem jest użycie out
parametru. out
Parametr jest identyczny z ref
parametrem z dodatkowym, kompilator egzekwowane reguły. Ta zasada mówi, że jeśli przekażesz out
parametr do funkcji, funkcja ta musi ustawić swoją wartość przed zwróceniem. Oprócz tej reguły out
parametr działa tak jak ref
parametr.
Ostatnim podejściem (i najlepszym w większości przypadków) jest stworzenie typu, który zawiera obie wartości i pozwala funkcji zwrócić:
class FooBar
{
public int i { get; set; }
public Bar b { get; set; }
}
FooBar Foo(Bar bar) { }
To końcowe podejście jest prostsze i łatwiejsze do odczytania i zrozumienia.
Nie, nie można zwrócić wielu wartości z funkcji w C # (dla wersji niższych niż C # 7), przynajmniej nie w sposób, w jaki można to zrobić w Pythonie.
Istnieje jednak kilka alternatyw:
Możesz zwrócić tablicę obiektu typu z wieloma wartościami, które chcesz w nim umieścić.
private object[] DoSomething()
{
return new [] { 'value1', 'value2', 3 };
}
Możesz użyć out
parametrów.
private string DoSomething(out string outparam1, out int outparam2)
{
outparam1 = 'value2';
outparam2 = 3;
return 'value1';
}
W C # 4 będziesz mógł użyć wbudowanej obsługi krotek, aby łatwo sobie z tym poradzić.
W międzyczasie istnieją dwie opcje.
Po pierwsze, możesz użyć parametrów ref lub out, aby przypisać wartości do parametrów, które są przekazywane z powrotem do procedury wywołującej.
To wygląda jak:
void myFunction(ref int setMe, out int youMustSetMe);
Po drugie, możesz zawijać zwracane wartości do struktury lub klasy i przekazywać je z powrotem jako członków tej struktury. KeyValuePair działa dobrze dla 2 - dla więcej niż 2 potrzebujesz niestandardowej klasy lub struktury.
możesz wypróbować ten „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);
Wynik :
Wyjście: 1, 2
Klasy, struktury, kolekcje i tablice mogą zawierać wiele wartości. Parametry wyjściowe i odniesienia można również ustawić w funkcji. Zwracanie wielu wartości jest możliwe w językach dynamicznych i funkcjonalnych za pomocą krotek, ale nie w języku C #.
Istnieją głównie dwie metody. 1. Użyj parametrów out / ref 2. Zwróć tablicę obiektów
Oto podstawowe Two
metody:
1) Użycie „ out
” jako parametru
Możesz użyć „out” zarówno dla wersji 4.0, jak i mniejszych.
Przykład „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();
}
}
}
Wynik:
Obszar prostokąta wynosi 20
Obwód prostokąta wynosi 18
* Uwaga: * out
Słowo-klucz opisuje parametry, których rzeczywiste lokalizacje zmiennych są kopiowane na stos wywoływanej metody, gdzie te same lokalizacje można przepisać. Oznacza to, że metoda wywołująca uzyska dostęp do zmienionego parametru.
2) Tuple<T>
Przykład krotki:
Zwracanie wielu wartości DataType za pomocą 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);
}
}
}
Wynik
perl
java
c#
1
2
3
UWAGA: Użycie Tuple jest ważne od Framework 4.0 i nowszych . Tuple
typ to class
. Zostanie przydzielony w oddzielnej lokalizacji na zarządzanej stercie w pamięci. Po utworzeniu Tuple
nie można zmienić jego wartości fields
. To sprawia, że Tuple
bardziej przypomina struct
.
Metoda przyjmująca delegata może dostarczyć rozmówcy wiele wartości. To zapożycza z mojej odpowiedzi tutaj i wykorzystuje trochę z zaakceptowanej odpowiedzi Hadasa .
delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
callback(1, 2);
}
Dzwoniący udostępniają lambda (lub nazwaną funkcję), a intellisense pomaga, kopiując nazwy zmiennych z delegata.
GetMultipleValues((upVotes, comments) =>
{
Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
Po prostu użyj w sposób OOP takiej klasy:
class div
{
public int remainder;
public int quotient(int dividend, int divisor)
{
remainder = ...;
return ...;
}
}
Członek funkcji zwraca iloraz, którym najbardziej interesuje większość dzwoniących. Dodatkowo przechowuje resztę jako element danych, do którego później dzwoniący może łatwo uzyskać dostęp.
W ten sposób możesz uzyskać wiele dodatkowych „wartości zwracanych”, bardzo przydatne, jeśli wykonujesz połączenia z bazą danych lub sieciami, gdzie może być potrzebnych wiele komunikatów o błędach, ale tylko w przypadku wystąpienia błędu.
Podałem to rozwiązanie również w pytaniu C ++, do którego odnosi się OP.
Przyszła wersja C # będzie zawierać nazwane krotki. Obejrzyj sesję channel9 dla wersji demo https://channel9.msdn.com/Events/Build/2016/B889
Przejdź do 13:00 po krotkę. Pozwoli to na takie rzeczy jak:
(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}
int resultsum = Tally(numbers).sum
(niekompletny przykład z filmu)
Możesz użyć obiektu dynamicznego. Myślę, że ma lepszą czytelność niż 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;
}
Sposoby na to:
1) KeyValuePair (najlepsza wydajność - 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) Krotka - 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 ns) lub ref 4) Stwórz własną klasę / strukturę
ns -> nanosekundy
Odniesienie: wielokrotne wartości zwrotne .
możesz tego spróbować
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
aby nie musieć jawnie tworzyć nowego string[]
?
Szybka odpowiedź specjalnie dla typów tablicowych zwraca:
private int[] SumAndSub(int A, int B)
{
return new[] { A + B, A - B };
}
Za pomocą:
var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[1];