Tôi đã đọc phiên bản C ++ của câu hỏi này nhưng không thực sự hiểu nó.
Ai đó có thể vui lòng giải thích rõ ràng nếu nó có thể được thực hiện và làm thế nào?
Tôi đã đọc phiên bản C ++ của câu hỏi này nhưng không thực sự hiểu nó.
Ai đó có thể vui lòng giải thích rõ ràng nếu nó có thể được thực hiện và làm thế nào?
Câu trả lời:
Trong C # 7 trở lên, xem câu trả lời này .
Trong các phiên bản trước, bạn có thể sử dụng Tuple của .NET 4.0 + :
Ví dụ:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
Tuples với hai giá trị có Item1
và Item2
là thuộc tính.
public (int sum, int count) GetMultipleValues() { return (1, 2); }
Ví dụ này được lấy từ ví dụ chủ đề Tài liệu của chúng tôi về điều này .
Bây giờ C # 7 đã được phát hành, bạn có thể sử dụng cú pháp Tuples mới được bao gồm
(string, string, string) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
mà sau đó có thể được sử dụng như thế này:
var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");
Bạn cũng có thể cung cấp tên cho các thành phần của mình (để chúng không phải là "Item1", "Item2", v.v.). Bạn có thể làm điều đó bằng cách thêm tên vào chữ ký hoặc các phương thức trả về:
(string first, string middle, string last) LookupName(long id) // tuple elements have names
hoặc là
return (first: first, middle: middle, last: last); // named tuple elements in a literal
Chúng cũng có thể được giải mã, đây là một tính năng mới khá hay:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
Kiểm tra liên kết này để xem thêm ví dụ về những gì có thể được thực hiện :)
Bạn có thể sử dụng ba cách khác nhau
1. tham số ref / out
sử dụng 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;
}
sử dụng
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. cấu trúc / lớp
sử dụng 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;
}
sử dụng lớp:
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. Bộ
Lớp học
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 Tuples
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);
}
Bạn không thể làm điều này trong C #. Những gì bạn có thể làm là có một out
tham số hoặc trả về lớp của riêng bạn (hoặc struct nếu bạn muốn nó là bất biến).
public int GetDay(DateTime date, out string name)
{
// ...
}
Sử dụng lớp tùy chỉnh (hoặc struct)
public DayOfWeek GetDay(DateTime date)
{
// ...
}
public class DayOfWeek
{
public int Day { get; set; }
public string Name { get; set; }
}
async
các phương pháp. Tuple
là con đường để đi (Tôi sử dụng out
các tham số trong các hoạt động đồng bộ mặc dù; chúng thực sự hữu ích trong các trường hợp đó.)
Nếu bạn có nghĩa là trả về nhiều giá trị, bạn có thể trả về một lớp / struct chứa các giá trị bạn muốn trả về hoặc sử dụng từ khóa "out" trên các tham số của bạn, như vậy:
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
Áp phích trước là đúng. Bạn không thể trả về nhiều giá trị từ phương thức C #. Tuy nhiên, bạn có một vài lựa chọn:
Những ưu và nhược điểm ở đây thường rất khó để tìm ra. Nếu bạn trả về một cấu trúc, hãy chắc chắn rằng nó nhỏ vì các cấu trúc là loại giá trị và được truyền vào ngăn xếp. Nếu bạn trả về một thể hiện của một lớp, có một số mẫu thiết kế ở đây mà bạn có thể muốn sử dụng để tránh gây ra sự cố - các thành viên của lớp có thể được sửa đổi vì C # chuyển các đối tượng theo tham chiếu (bạn không có ByVal như bạn đã làm trong VB ).
Cuối cùng, bạn có thể sử dụng các tham số đầu ra nhưng tôi sẽ giới hạn việc sử dụng tham số này cho các kịch bản khi bạn chỉ có một vài (như 3 hoặc ít hơn) các tham số - nếu không mọi thứ trở nên xấu và khó bảo trì. Ngoài ra, việc sử dụng các tham số đầu ra có thể là một yếu tố ngăn cản sự linh hoạt bởi vì chữ ký phương thức của bạn sẽ phải thay đổi mỗi khi bạn cần thêm một cái gì đó vào giá trị trả về trong khi trả về một cá thể cấu trúc hoặc lớp mà bạn có thể thêm thành viên mà không sửa đổi chữ ký phương thức.
Từ quan điểm kiến trúc, tôi khuyên bạn không nên sử dụng các cặp từ điển hoặc giá trị khóa. Tôi thấy phong cách mã hóa này đòi hỏi "kiến thức bí mật" trong mã tiêu thụ phương thức. Nó phải biết trước các khóa sẽ là gì và các giá trị có ý nghĩa gì và nếu nhà phát triển làm việc triển khai nội bộ thay đổi cách tạo từ điển hoặc KVP, nó có thể dễ dàng tạo ra một tầng thất bại trong toàn bộ ứng dụng.
Exception
nếu giá trị thứ hai bạn muốn trả về là khác biệt so với giá trị thứ nhất: như khi bạn muốn trả về một loại giá trị thành công hoặc một loại giá trị không thành công.
Bạn có thể trả về một cá thể của lớp hoặc sử dụng ra các thông số. Đây là một ví dụ về các tham số ngoài:
void mymethod(out int param1, out int param2)
{
param1 = 10;
param2 = 20;
}
Gọi nó như thế này:
int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10
Có nhiều cách; nhưng nếu bạn không muốn tạo Đối tượng hoặc cấu trúc mới hoặc một cái gì đó như thế này, bạn có thể thực hiện như bên dưới sau 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");
}
Trong C # 7 Có một Tuple
cú pháp mới :
static (string foo, int bar) GetTuple()
{
return ("hello", 5);
}
Bạn có thể trả lại đây là một bản ghi:
var result = GetTuple();
var foo = result.foo
// foo == "hello"
Bạn cũng có thể sử dụng cú pháp giải mã mới:
(string foo) = GetTuple();
// foo == "hello"
Tuy nhiên, hãy cẩn thận với việc tuần tự hóa, tất cả điều này là đường cú pháp - trong mã được biên dịch thực tế, đây sẽ là một Tuple<string, int>
(theo câu trả lời được chấp nhận ) với Item1
và Item2
thay vì foo
và bar
. Điều đó có nghĩa là việc tuần tự hóa (hoặc khử lưu huỳnh) sẽ sử dụng các tên thuộc tính đó để thay thế.
Vì vậy, để tuần tự hóa khai báo một lớp bản ghi và trả lại thay thế.
Điểm mới trong C # 7 là một cú pháp cải tiến cho out
các tham số. Bây giờ bạn có thể khai báo out
nội tuyến, phù hợp hơn trong một số ngữ cảnh:
if(int.TryParse("123", out int result)) {
// Do something with result
}
Tuy nhiên, chủ yếu bạn sẽ sử dụng điều này trong các thư viện riêng của .NET, thay vì trong các chức năng của riêng bạn.
Một số câu trả lời đề nghị sử dụng các tham số nhưng tôi khuyên bạn không nên sử dụng tham số này do chúng không hoạt động với các phương thức không đồng bộ . Xem điều này để biết thêm thông tin.
Các câu trả lời khác được nêu bằng Tuple, tôi cũng muốn giới thiệu nhưng sử dụng tính năng mới được giới thiệu trong 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}.");
Thông tin chi tiết có thể được tìm thấy ở đây .
Có nhiều hướng khác nhau để làm điều đó. Bạn có thể sử dụng ref
các tham số:
int Foo(ref Bar bar) { }
Điều này chuyển một tham chiếu đến hàm do đó cho phép hàm sửa đổi đối tượng trong ngăn xếp của mã gọi. Mặc dù về mặt kỹ thuật, đây không phải là một giá trị "được trả về", đó là một cách để một hàm làm điều gì đó tương tự. Trong đoạn mã trên, hàm sẽ trả về int
và (có khả năng) sửa đổi bar
.
Một cách tiếp cận tương tự khác là sử dụng một out
tham số. Một out
tham số giống hệt với ref
tham số có quy tắc thực thi bổ sung, trình biên dịch. Quy tắc này là nếu bạn truyền out
tham số vào hàm, hàm đó được yêu cầu để đặt giá trị của nó trước khi trả về. Bên cạnh quy tắc đó, một out
tham số hoạt động giống như một ref
tham số.
Cách tiếp cận cuối cùng (và tốt nhất trong hầu hết các trường hợp) là tạo ra một kiểu đóng gói cả hai giá trị và cho phép hàm trả về giá trị đó:
class FooBar
{
public int i { get; set; }
public Bar b { get; set; }
}
FooBar Foo(Bar bar) { }
Cách tiếp cận cuối cùng này đơn giản và dễ đọc và dễ hiểu hơn.
Không, bạn không thể trả về nhiều giá trị từ một hàm trong C # (đối với các phiên bản thấp hơn C # 7), ít nhất là không theo cách bạn có thể thực hiện trong Python.
Tuy nhiên, có một vài lựa chọn thay thế:
Bạn có thể trả về một mảng của đối tượng kiểu với nhiều giá trị bạn muốn trong đó.
private object[] DoSomething()
{
return new [] { 'value1', 'value2', 3 };
}
Bạn có thể sử dụng out
các tham số.
private string DoSomething(out string outparam1, out int outparam2)
{
outparam1 = 'value2';
outparam2 = 3;
return 'value1';
}
Trong C # 4, bạn sẽ có thể sử dụng hỗ trợ tích hợp cho các bộ dữ liệu để xử lý việc này một cách dễ dàng.
Trong khi đó, có hai lựa chọn.
Đầu tiên, bạn có thể sử dụng tham số ref hoặc out để gán giá trị cho tham số của mình, được chuyển trở lại thói quen gọi.
Điều này trông giống như:
void myFunction(ref int setMe, out int youMustSetMe);
Thứ hai, bạn có thể gói các giá trị trả về của mình vào một cấu trúc hoặc lớp và chuyển chúng trở lại là thành viên của cấu trúc đó. KeyValuePair hoạt động tốt cho 2 - trong hơn 2 bạn sẽ cần một lớp hoặc cấu trúc tùy chỉnh.
bạn có thể thử "KeyValuePair" này
private KeyValuePair<int, int> GetNumbers()
{
return new KeyValuePair<int, int>(1, 2);
}
var numbers = GetNumbers();
Console.WriteLine("Output : {0}, {1}",numbers.Key, numbers.Value);
Đầu ra:
Đầu ra: 1, 2
Các lớp, cấu trúc, bộ sưu tập và mảng có thể chứa nhiều giá trị. Các tham số đầu ra và tham chiếu cũng có thể được đặt trong một hàm. Trả về nhiều giá trị có thể có trong các ngôn ngữ động và chức năng bằng các bộ dữ liệu, nhưng không có trong C #.
Chủ yếu có hai phương pháp. 1. Sử dụng tham số out / ref 2. Trả về một mảng các đối tượng
Dưới đây là các Two
phương pháp cơ bản :
1) Sử dụng ' out
' làm tham số
Bạn cũng có thể sử dụng 'out' cho cả phiên bản 4.0 và phiên bản nhỏ.
Ví dụ về 'ra':
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();
}
}
}
Đầu ra:
Diện tích hình chữ nhật là 20
Chu vi của hình chữ nhật là 18
* Lưu ý: * Từ khóa out
mô tả các tham số có vị trí biến thực tế được sao chép vào ngăn xếp của phương thức được gọi, trong đó các vị trí tương tự có thể được viết lại. Điều này có nghĩa là phương thức gọi sẽ truy cập vào tham số đã thay đổi.
2) Tuple<T>
Ví dụ về Tuple:
Trả về nhiều giá trị DataType bằng cách sử dụng 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);
}
}
}
Đầu ra
perl
java
c#
1
2
3
LƯU Ý: Việc sử dụng Tuple có hiệu lực từ Khung 4.0 trở lên . Tuple
loại là a class
. Nó sẽ được phân bổ ở một vị trí riêng biệt trên heap được quản lý trong bộ nhớ. Khi bạn tạo Tuple
, bạn không thể thay đổi giá trị của nó fields
. Điều này làm cho Tuple
giống như a struct
.
Một phương thức lấy một đại biểu có thể cung cấp nhiều giá trị cho người gọi. Điều này mượn từ câu trả lời của tôi ở đây và sử dụng một chút từ câu trả lời được chấp nhận của Hadas .
delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
callback(1, 2);
}
Người gọi cung cấp một lambda (hoặc một chức năng được đặt tên) và intellisense giúp bằng cách sao chép tên biến từ đại biểu.
GetMultipleValues((upVotes, comments) =>
{
Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
Chỉ cần sử dụng theo cách OOP một lớp như thế này:
class div
{
public int remainder;
public int quotient(int dividend, int divisor)
{
remainder = ...;
return ...;
}
}
Thành viên hàm trả về thương số mà hầu hết người gọi chủ yếu quan tâm. Ngoài ra, nó lưu phần còn lại dưới dạng thành viên dữ liệu, người gọi có thể dễ dàng truy cập sau đó.
Bằng cách này, bạn có thể có nhiều "giá trị trả về" bổ sung, rất hữu ích nếu bạn triển khai cơ sở dữ liệu hoặc các cuộc gọi mạng, trong đó có thể cần nhiều thông báo lỗi nhưng chỉ trong trường hợp xảy ra lỗi.
Tôi cũng đã nhập giải pháp này trong câu hỏi C ++ mà OP đang đề cập.
Phiên bản tương lai của C # sẽ bao gồm các bộ dữ liệu được đặt tên. Hãy xem phiên channel9 này để xem demo https://channel9.msdn.com/Events/Build/2016/B889
Bỏ qua đến 13:00 cho các công cụ tuple. Điều này sẽ cho phép những thứ như:
(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}
int resultsum = Tally(numbers).sum
(ví dụ không đầy đủ từ video)
Bạn có thể sử dụng một đối tượng động. Tôi nghĩ rằng nó có khả năng đọc tốt hơn 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;
}
Cách thực hiện:
1) KeyValuePair (Hiệu suất tốt nhất - 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) Tuple - 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) hoặc ref 4) Tạo lớp / struct tùy chỉnh của riêng bạn
ns -> nano giây
Tham khảo: nhiều giá trị trả về .
bạn có thể thử cái này
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
để không phải tạo một cái mới rõ ràng string[]
?
Bạn cũng có thể sử dụng một 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;
}
Một câu trả lời nhanh đặc biệt cho trả về kiểu mảng:
private int[] SumAndSub(int A, int B)
{
return new[] { A + B, A - B };
}
Sử dụng:
var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[1];