Ich habe die C ++ - Version dieser Frage gelesen , aber nicht wirklich verstanden.
Kann jemand bitte klar erklären, ob und wie es geht?
Ich habe die C ++ - Version dieser Frage gelesen , aber nicht wirklich verstanden.
Kann jemand bitte klar erklären, ob und wie es geht?
Antworten:
In C # 7 und höher finden Sie diese Antwort .
In früheren Versionen können Sie das Tupel von .NET 4.0 + verwenden :
Zum Beispiel:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
Tupel mit zwei Werten haben Item1
und Item2
als Eigenschaften.
public (int sum, int count) GetMultipleValues() { return (1, 2); }
Dieses Beispiel stammt aus unserem Beispiel zum Thema Dokumentation .
Nachdem C # 7 veröffentlicht wurde, können Sie die neu enthaltene Tuples-Syntax verwenden
(string, string, string) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
was dann so verwendet werden könnte:
var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");
Sie können Ihren Elementen auch Namen geben (sie sind also nicht "Item1", "Item2" usw.). Sie können dies tun, indem Sie der Signatur oder den Rückgabemethoden einen Namen hinzufügen:
(string first, string middle, string last) LookupName(long id) // tuple elements have names
oder
return (first: first, middle: middle, last: last); // named tuple elements in a literal
Sie können auch dekonstruiert werden, was eine ziemlich nette neue Funktion ist:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
Schauen Sie sich diesen Link an, um weitere Beispiele zu sehen, was getan werden kann :)
Sie können drei verschiedene Möglichkeiten verwenden
1. Ref / Out-Parameter
mit 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;
}
Verwenden von:
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. Struktur / Klasse
using 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;
}
using class:
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. Tupel
Tupelklasse
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 Tupel
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);
}
Sie können dies nicht in C # tun. Was Sie tun können, ist eineout
Parameter haben oder eine eigene Klasse zurückgeben (oder eine Struktur, wenn diese unveränderlich sein soll).
public int GetDay(DateTime date, out string name)
{
// ...
}
Verwenden einer benutzerdefinierten Klasse (oder Struktur)
public DayOfWeek GetDay(DateTime date)
{
// ...
}
public class DayOfWeek
{
public int Day { get; set; }
public string Name { get; set; }
}
async
Methoden nicht möglich . Tuple
ist der Weg zu gehen. (Ich verwende jedoch out
Parameter in synchronen Operationen; sie sind in diesen Fällen tatsächlich nützlich.)
Wenn Sie mehrere Werte zurückgeben möchten, können Sie entweder eine Klasse / Struktur zurückgeben, die die Werte enthält, die Sie zurückgeben möchten, oder das Schlüsselwort "out" für Ihre Parameter verwenden, z.
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
Vorheriges Poster ist richtig. Sie können nicht mehrere Werte von einer C # -Methode zurückgeben. Sie haben jedoch einige Möglichkeiten:
Die Vor- und Nachteile sind hier oft schwer herauszufinden. Wenn Sie eine Struktur zurückgeben, stellen Sie sicher, dass sie klein ist, da Strukturen vom Werttyp sind und an den Stapel übergeben werden. Wenn Sie eine Instanz einer Klasse zurückgeben, gibt es hier einige Entwurfsmuster, die Sie möglicherweise verwenden möchten, um Probleme zu vermeiden. Mitglieder von Klassen können geändert werden, da C # Objekte als Referenz übergibt (Sie haben ByVal nicht wie in VB ).
Schließlich können Sie Ausgabeparameter verwenden, aber ich würde die Verwendung auf Szenarien beschränken, in denen Sie nur ein paar (wie 3 oder weniger) Parameter haben - andernfalls werden die Dinge hässlich und schwer zu warten. Die Verwendung von Ausgabeparametern kann auch die Agilität beeinträchtigen, da sich Ihre Methodensignatur jedes Mal ändern muss, wenn Sie dem Rückgabewert etwas hinzufügen müssen, während Sie bei der Rückgabe einer Struktur- oder Klasseninstanz Mitglieder hinzufügen können, ohne die Methodensignatur zu ändern.
Aus architektonischer Sicht würde ich empfehlen, keine Schlüssel-Wert-Paare oder Wörterbücher zu verwenden. Ich finde, dass diese Art der Codierung "geheimes Wissen" in Code erfordert, der die Methode verbraucht. Es muss im Voraus wissen, wie die Schlüssel lauten und was die Werte bedeuten. Wenn der Entwickler, der an der internen Implementierung arbeitet, die Art und Weise ändert, in der das Wörterbuch oder KVP erstellt wird, kann dies leicht zu einer Fehlerkaskade in der gesamten Anwendung führen.
Exception
Wert auslösen, wenn der zweite Wert, den Sie zurückgeben möchten, nicht mit dem ersten Wert übereinstimmt: Zum Beispiel, wenn Sie entweder eine Art erfolgreichen Wert oder eine Art erfolglosen Wert zurückgeben möchten.
Sie entweder eine Rückkehr Klasseninstanz oder verwenden out - Parameter. Hier ist ein Beispiel für unsere Parameter:
void mymethod(out int param1, out int param2)
{
param1 = 10;
param2 = 20;
}
Nennen Sie es so:
int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10
Es gibt viele Wege; Wenn Sie jedoch kein neues Objekt oder keine neue Struktur oder ähnliches erstellen möchten, können Sie dies nach C # 7.0 wie folgt tun :
(string firstName, string lastName) GetName(string myParameter)
{
var firstName = myParameter;
var lastName = myParameter + " something";
return (firstName, lastName);
}
void DoSomethingWithNames()
{
var (firstName, lastName) = GetName("myname");
}
In C # 7 gibt es eine neue Tuple
Syntax:
static (string foo, int bar) GetTuple()
{
return ("hello", 5);
}
Sie können dies als Datensatz zurückgeben:
var result = GetTuple();
var foo = result.foo
// foo == "hello"
Sie können auch die neue Dekonstruktorsyntax verwenden:
(string foo) = GetTuple();
// foo == "hello"
Seien Sie jedoch vorsichtig mit der Serialisierung, dies ist alles syntaktischer Zucker - im tatsächlich kompilierten Code ist dies ein Tuple<string, int>
( gemäß der akzeptierten Antwort ) mit Item1
und Item2
anstelle von foo
undbar
. Das bedeutet, dass bei der Serialisierung (oder Deserialisierung) stattdessen diese Eigenschaftsnamen verwendet werden.
Deklarieren Sie für die Serialisierung eine Datensatzklasse und geben Sie diese stattdessen zurück.
Ebenfalls neu in C # 7 ist eine verbesserte Syntax für out
Parameter. Sie können jetzt die out
Inline deklarieren , die in einigen Kontexten besser geeignet ist:
if(int.TryParse("123", out int result)) {
// Do something with result
}
Meistens verwenden Sie dies jedoch in .NET-eigenen Bibliotheken und nicht in Ihren eigenen Funktionen.
Einige Antworten schlagen vor , Parameter zu verwenden, aber ich empfehle, diese nicht zu verwenden, da sie nicht mit asynchronen Methoden funktionieren . Sehen Sie diese für weitere Informationen.
Andere Antworten wurden mit Tuple angegeben, was ich auch empfehlen würde, aber mit der neuen Funktion, die in C # 7.0 eingeführt wurde.
(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}.");
Weitere Informationen finden Sie hier .
Es gibt verschiedene Möglichkeiten, dies zu tun. Sie können ref
Parameter verwenden:
int Foo(ref Bar bar) { }
Dies übergibt einen Verweis auf die Funktion, wodurch die Funktion das Objekt im Stapel des aufrufenden Codes ändern kann. Obwohl dies technisch gesehen kein "zurückgegebener" Wert ist, ist es eine Möglichkeit, eine Funktion etwas Ähnliches tun zu lassen. Im obigen Code würde die Funktion ein int
und (möglicherweise) eine Änderung zurückgeben bar
.
Ein anderer ähnlicher Ansatz ist die Verwendung eines out
Parameters. Ein out
Parameter ist identisch mit einem ref
Parameter mit einer zusätzlichen, vom Compiler erzwungenen Regel. Diese Regel lautet: Wenn Sie einen out
Parameter an eine Funktion übergeben, muss diese Funktion ihren Wert vor der Rückgabe festlegen. Neben dieser Regel out
funktioniert ein Parameter genau wie ein ref
Parameter.
Der letzte Ansatz (und in den meisten Fällen der beste) besteht darin, einen Typ zu erstellen, der beide Werte kapselt und es der Funktion ermöglicht, Folgendes zurückzugeben:
class FooBar
{
public int i { get; set; }
public Bar b { get; set; }
}
FooBar Foo(Bar bar) { }
Dieser endgültige Ansatz ist einfacher und leichter zu lesen und zu verstehen.
Nein, Sie können nicht mehrere Werte von einer Funktion in C # zurückgeben (für Versionen unter C # 7), zumindest nicht so, wie Sie es in Python tun können.
Es gibt jedoch einige Alternativen:
Sie können ein Array vom Typ Objekt mit den gewünschten Werten zurückgeben.
private object[] DoSomething()
{
return new [] { 'value1', 'value2', 3 };
}
Sie können out
Parameter verwenden.
private string DoSomething(out string outparam1, out int outparam2)
{
outparam1 = 'value2';
outparam2 = 3;
return 'value1';
}
In C # 4 können Sie die integrierte Unterstützung für Tupel verwenden, um dies einfach zu handhaben.
In der Zwischenzeit gibt es zwei Möglichkeiten.
Zunächst können Sie ref- oder out-Parameter verwenden, um Ihren Parametern Werte zuzuweisen, die an die aufrufende Routine zurückgegeben werden.
Das sieht so aus:
void myFunction(ref int setMe, out int youMustSetMe);
Zweitens können Sie Ihre Rückgabewerte in eine Struktur oder Klasse einschließen und sie als Mitglieder dieser Struktur zurückgeben. KeyValuePair funktioniert gut für 2 - für mehr als 2 benötigen Sie eine benutzerdefinierte Klasse oder Struktur.
Sie können dieses "KeyValuePair" ausprobieren
private KeyValuePair<int, int> GetNumbers()
{
return new KeyValuePair<int, int>(1, 2);
}
var numbers = GetNumbers();
Console.WriteLine("Output : {0}, {1}",numbers.Key, numbers.Value);
Ausgabe :
Ausgabe: 1, 2
Klassen, Strukturen, Sammlungen und Arrays können mehrere Werte enthalten. Ausgabe- und Referenzparameter können auch in einer Funktion eingestellt werden. Die Rückgabe mehrerer Werte ist in dynamischen und funktionalen Sprachen mithilfe von Tupeln möglich, jedoch nicht in C #.
Es gibt hauptsächlich zwei Methoden. 1. Verwenden Sie out / ref-Parameter. 2. Geben Sie ein Array von Objekten zurück
Hier sind grundlegende Two
Methoden:
1) Verwendung von ' out
' als Parameter
Sie können 'out' sowohl für 4.0- als auch für Nebenversionen verwenden.
Beispiel für '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();
}
}
}
Ausgabe:
Die Fläche des Rechtecks beträgt 20
Der Umfang des Rechtecks beträgt 18
* Hinweis: * Das out
Schlüsselwort -key beschreibt Parameter, deren tatsächliche Variablenpositionen auf den Stapel der aufgerufenen Methode kopiert werden, wo dieselben Positionen neu geschrieben werden können. Dies bedeutet, dass die aufrufende Methode auf den geänderten Parameter zugreift.
2) Tuple<T>
Beispiel für Tupel:
Rückgabe mehrerer DataType-Werte mit 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);
}
}
}
Ausgabe
perl
java
c#
1
2
3
HINWEIS: Die Verwendung von Tuple ist ab Framework 4.0 gültig . Tuple
Typ ist a class
. Es wird an einem separaten Speicherort auf dem verwalteten Heap im Speicher zugewiesen. Sobald Sie das erstellt haben Tuple
, können Sie die Werte nicht mehr ändern fields
. Dies macht das Tuple
eher wie ein struct
.
Eine Methode, die einen Delegaten verwendet, kann dem Aufrufer mehrere Werte bereitstellen. Dies entlehnt meiner Antwort hier und verwendet ein wenig von Hadas akzeptierter Antwort .
delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
callback(1, 2);
}
Anrufer stellen ein Lambda (oder eine benannte Funktion) bereit, und Intellisense hilft beim Kopieren der Variablennamen vom Delegaten.
GetMultipleValues((upVotes, comments) =>
{
Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
Verwenden Sie einfach in OOP-Weise eine Klasse wie diese:
class div
{
public int remainder;
public int quotient(int dividend, int divisor)
{
remainder = ...;
return ...;
}
}
Das Funktionselement gibt den Quotienten zurück, an dem die meisten Anrufer hauptsächlich interessiert sind. Außerdem speichert es den Rest als Datenelement, auf das der Anrufer anschließend leicht zugreifen kann.
Auf diese Weise können Sie viele zusätzliche "Rückgabewerte" haben, die sehr nützlich sind, wenn Sie Datenbank- oder Netzwerkaufrufe implementieren, bei denen viele Fehlermeldungen erforderlich sein können, jedoch nur im Falle eines Fehlers.
Ich habe diese Lösung auch in die C ++ - Frage eingegeben, auf die sich OP bezieht.
Die zukünftige Version von C # wird benannte Tupel enthalten. Schauen Sie sich diese Channel9-Sitzung für die Demo an https://channel9.msdn.com/Events/Build/2016/B889
Springe zu 13:00 für das Tupel-Zeug. Dies ermöglicht Dinge wie:
(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}
int resultsum = Tally(numbers).sum
(unvollständiges Beispiel aus Video)
Sie können ein dynamisches Objekt verwenden. Ich denke, es hat eine bessere Lesbarkeit als 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;
}
Möglichkeiten, es zu tun:
1) KeyValuePair (beste Leistung - 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) Tupel - 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) oder ref 4) Erstellen Sie Ihre eigene benutzerdefinierte Klasse / Struktur
ns -> Nanosekunden
Referenz: Multiple-Return-Werte .
Sie können dies versuchen
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
, um nicht explizit ein neues erstellen zu müssen string[]
?
Sie können auch ein OperationResult verwenden
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;
}
Eine schnelle Antwort speziell für Array-Typ-Rückgaben:
private int[] SumAndSub(int A, int B)
{
return new[] { A + B, A - B };
}
Verwenden von:
var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[1];