Ho letto la versione C ++ di questa domanda ma non l'ho capito davvero.
Qualcuno può spiegare chiaramente se si può fare e come?
Ho letto la versione C ++ di questa domanda ma non l'ho capito davvero.
Qualcuno può spiegare chiaramente se si può fare e come?
Risposte:
In C # 7 e versioni successive, vedi questa risposta .
Nelle versioni precedenti, puoi usare Tuple di .NET 4.0+ :
Per esempio:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
Le tuple con due valori hanno Item1
e Item2
come proprietà.
public (int sum, int count) GetMultipleValues() { return (1, 2); }
Questo esempio è stato preso dal nostro esempio di argomento Documentazione su questo .
Ora che C # 7 è stato rilasciato, puoi usare la nuova sintassi di Tuples inclusa
(string, string, string) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
che potrebbe quindi essere utilizzato in questo modo:
var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");
Puoi anche fornire nomi ai tuoi elementi (quindi non sono "Item1", "Item2" ecc.). Puoi farlo aggiungendo un nome alla firma o ai metodi di restituzione:
(string first, string middle, string last) LookupName(long id) // tuple elements have names
o
return (first: first, middle: middle, last: last); // named tuple elements in a literal
Possono anche essere decostruiti, che è una nuova caratteristica piuttosto carina:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
Dai un'occhiata a questo link per vedere altri esempi di cosa si può fare :)
Puoi usare tre modi diversi
1. parametri ref / out
usando 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;
}
utilizzando:
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
usando 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;
}
usando la classe:
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. Tupla
Classe Tupla
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;
}
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);
}
Non puoi farlo in C #. Quello che puoi fare è avere un out
parametro o restituire la tua classe (o struct se vuoi che sia immutabile).
public int GetDay(DateTime date, out string name)
{
// ...
}
Utilizzo della classe personalizzata (o struct)
public DayOfWeek GetDay(DateTime date)
{
// ...
}
public class DayOfWeek
{
public int Day { get; set; }
public string Name { get; set; }
}
async
metodi. Tuple
è la strada da percorrere. (Uso i out
parametri nelle operazioni sincrone però; sono davvero utili in quei casi.)
Se intendi restituire più valori, puoi restituire una classe / struttura contenente i valori che desideri restituire oppure utilizzare la parola chiave "out" sui tuoi parametri, in questo modo:
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
Il poster precedente ha ragione. Non è possibile restituire più valori da un metodo C #. Tuttavia, hai un paio di opzioni:
I pro ei contro qui sono spesso difficili da capire. Se si restituisce una struttura, assicurarsi che sia piccola perché le strutture sono di tipo valore e passate sullo stack. Se restituisci un'istanza di una classe, qui ci sono alcuni schemi di progettazione che potresti voler usare per evitare di causare problemi - i membri delle classi possono essere modificati perché C # passa oggetti per riferimento (non hai ByVal come in VB ).
Finalmente puoi usare i parametri di output ma limiterei l'uso di questo agli scenari quando hai solo un paio (come 3 o meno) di parametri - altrimenti le cose diventano brutte e difficili da mantenere. Inoltre, l'uso dei parametri di output può essere un inibitore dell'agilità poiché la firma del metodo dovrà cambiare ogni volta che è necessario aggiungere qualcosa al valore restituito, mentre restituendo un'istanza di struttura o classe è possibile aggiungere membri senza modificare la firma del metodo.
Da un punto di vista architettonico, consiglierei di non utilizzare coppie chiave-valore o dizionari. Trovo che questo stile di codifica richieda "conoscenza segreta" nel codice che consuma il metodo. Deve sapere in anticipo quali saranno le chiavi e cosa significano i valori e se lo sviluppatore che lavora sull'implementazione interna cambia il modo in cui viene creato il dizionario o KVP, potrebbe facilmente creare una cascata di errori nell'intera applicazione.
Exception
se il secondo valore che vuoi restituire è disgiuntivo dal primo: come quando vuoi restituire una sorta di valore di successo, o una sorta di valore senza successo.
Si restituisce un'istanza di classe o si utilizzano i parametri. Ecco un esempio di parametri out:
void mymethod(out int param1, out int param2)
{
param1 = 10;
param2 = 20;
}
Chiamalo così:
int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10
C'è molti modi; ma se non vuoi creare un nuovo oggetto o struttura o qualcosa del genere, puoi fare come segue dopo 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");
}
In C # 7 Esiste una nuova Tuple
sintassi:
static (string foo, int bar) GetTuple()
{
return ("hello", 5);
}
Puoi restituirlo come record:
var result = GetTuple();
var foo = result.foo
// foo == "hello"
Puoi anche usare la nuova sintassi del decostruttore:
(string foo) = GetTuple();
// foo == "hello"
Fai attenzione con la serializzazione, tuttavia, tutto questo è zucchero sintattico - nel codice compilato effettivo questo sarà un Tuple<string, int>
(come per la risposta accettata ) con Item1
e Item2
invece di foo
e bar
. Ciò significa che la serializzazione (o la deserializzazione) utilizzerà invece quei nomi di proprietà.
Quindi, per la serializzazione dichiarare una classe record e restituirla invece.
Un'altra novità di C # 7 è una sintassi migliorata per i out
parametri. Ora puoi dichiarare l' out
inline, che è più adatto in alcuni contesti:
if(int.TryParse("123", out int result)) {
// Do something with result
}
Tuttavia, per lo più lo userete nelle librerie di .NET, piuttosto che nelle vostre stesse funzioni.
Alcune risposte suggeriscono di utilizzare i parametri, ma consiglio di non utilizzarlo perché non funzionano con i metodi asincroni . Vedi questo per maggiori informazioni.
Altre risposte dichiarate usando Tuple, che consiglierei anche io ma usando la nuova funzionalità introdotta in 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}.");
Ulteriori informazioni sono disponibili qui .
Esistono diversi modi per farlo. È possibile utilizzare i ref
parametri:
int Foo(ref Bar bar) { }
Questo passa un riferimento alla funzione permettendo così alla funzione di modificare l'oggetto nello stack del codice chiamante. Sebbene questo non sia tecnicamente un valore "restituito", è un modo per fare in modo che una funzione faccia qualcosa di simile. Nel codice sopra la funzione restituirebbe una int
(e potenzialmente) modifica bar
.
Un altro approccio simile è usare un out
parametro. Un out
parametro è identico a un ref
parametro con una regola aggiuntiva applicata dal compilatore. Questa regola prevede che se si passa un out
parametro a una funzione, tale funzione è richiesta per impostarne il valore prima di tornare. Oltre a quella regola, un out
parametro funziona esattamente come un ref
parametro.
L'approccio finale (e il migliore nella maggior parte dei casi) è quello di creare un tipo che incapsuli entrambi i valori e consenta alla funzione di restituire che:
class FooBar
{
public int i { get; set; }
public Bar b { get; set; }
}
FooBar Foo(Bar bar) { }
Questo approccio finale è più semplice e più facile da leggere e comprendere.
No, non puoi restituire più valori da una funzione in C # (per versioni inferiori a C # 7), almeno non nel modo in cui puoi farlo in Python.
Tuttavia, ci sono un paio di alternative:
È possibile restituire una matrice di tipo oggetto con i valori multipli che si desidera in esso.
private object[] DoSomething()
{
return new [] { 'value1', 'value2', 3 };
}
È possibile utilizzare i out
parametri.
private string DoSomething(out string outparam1, out int outparam2)
{
outparam1 = 'value2';
outparam2 = 3;
return 'value1';
}
In C # 4, sarai in grado di utilizzare il supporto integrato per le tuple per gestirlo facilmente.
Nel frattempo, ci sono due opzioni.
Innanzitutto, è possibile utilizzare i parametri ref o out per assegnare valori ai parametri, che vengono passati alla routine di chiamata.
Questo sembra:
void myFunction(ref int setMe, out int youMustSetMe);
In secondo luogo, è possibile racchiudere i valori restituiti in una struttura o classe e restituirli come membri di quella struttura. KeyValuePair funziona bene per 2 - per più di 2 avrai bisogno di una classe o struttura personalizzata.
puoi provare questo "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);
Produzione :
Uscita: 1, 2
Classi, strutture, raccolte e matrici possono contenere più valori. I parametri di uscita e riferimento possono anche essere impostati in una funzione. Restituire più valori è possibile in linguaggi dinamici e funzionali per mezzo di tuple, ma non in C #.
Principalmente ci sono due metodi. 1. Utilizzare i parametri out / ref 2. Restituire una matrice di oggetti
Ecco i Two
metodi di base :
1) Uso di ' out
' come parametro
Puoi usare 'out' sia per la versione 4.0 che per quella minore.
Esempio di "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();
}
}
}
Produzione:
L'area del rettangolo è 20
Il perimetro del rettangolo è 18
* Nota: * La out
parola chiave descrive i parametri le cui posizioni delle variabili effettive vengono copiate nello stack del metodo chiamato, in cui è possibile riscrivere quelle stesse posizioni. Ciò significa che il metodo chiamante accederà al parametro modificato.
2) Tuple<T>
Esempio di Tupla:
Restituzione di più valori DataType utilizzando 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);
}
}
}
Produzione
perl
java
c#
1
2
3
NOTA: l' uso di Tuple è valido da Framework 4.0 e versioni successive . Tuple
il tipo è a class
. Sarà allocato in una posizione separata sull'heap gestito in memoria. Una volta creato Tuple
, non è possibile modificarne i valori fields
. Questo rende Tuple
più simile a struct
.
Un metodo che accetta un delegato può fornire più valori al chiamante. Questo prende in prestito dalla mia risposta qui e usa un po 'dalla risposta accettata di Hadas .
delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
callback(1, 2);
}
I chiamanti forniscono una lambda (o una funzione denominata) e intellisense aiuta copiando i nomi delle variabili dal delegato.
GetMultipleValues((upVotes, comments) =>
{
Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
Basta usare in modo OOP una classe come questa:
class div
{
public int remainder;
public int quotient(int dividend, int divisor)
{
remainder = ...;
return ...;
}
}
Il membro della funzione restituisce il quoziente a cui la maggior parte dei chiamanti è principalmente interessato. Inoltre, memorizza il resto come membro di dati, che è facilmente accessibile dal chiamante in seguito.
In questo modo è possibile avere molti "valori di ritorno" aggiuntivi, molto utili se si implementano chiamate di database o di rete, in cui potrebbero essere necessari molti messaggi di errore ma solo nel caso si verifichi un errore.
Ho inserito questa soluzione anche nella domanda C ++ a cui OP si riferisce.
La versione futura di C # includerà le tuple nominate. Dai un'occhiata a questa sessione di channel9 per la demo https://channel9.msdn.com/Events/Build/2016/B889
Passa alle 13:00 per la roba tupla. Ciò consentirà cose come:
(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}
int resultsum = Tally(numbers).sum
(esempio incompleto dal video)
È possibile utilizzare un oggetto dinamico. Penso che abbia una migliore leggibilità rispetto a 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;
}
Modi per farlo:
1) KeyValuePair (Best Performance - 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) Tupla - 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) o ref 4) Crea la tua classe / struttura personalizzata
ns -> nanosecondi
Riferimento: valori di ritorno multipli .
puoi provare questo
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
come non dover creare esplicitamente un nuovo string[]
?
È inoltre possibile utilizzare un 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;
}
Una risposta rapida appositamente per i tipi di array restituisce:
private int[] SumAndSub(int A, int B)
{
return new[] { A + B, A - B };
}
usando:
var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[1];