How can I return multiple values from a function in C#?
我读了这个问题的C++版本,但并没有真正理解它。
如果可以的话,有人能解释清楚吗?如何解释?
使用.NET 4.0+的元组:
例如:
1 2 3 4 | public Tuple<int, int> GetMultipleValue() { return Tuple.Create(1,2); } |
具有两个值的元组的属性为
既然C 7已经发布,您可以使用新的包含元组语法
1 2 3 4 5 | (string, string, string) LookupName(long id) // tuple return type { ... // retrieve first, middle and last from data storage return (first, middle, last); // tuple literal } |
然后可以这样使用:
1 2 | var names = LookupName(id); WriteLine($"found {names.Item1} {names.Item3}."); |
您还可以为元素提供名称(因此它们不是"item1"、"item2"等)。您可以通过在签名或返回方法中添加名称来完成此操作:
1 | (string first, string middle, string last) LookupName(long id) // tuple elements have names |
或
1 | return (first: first, middle: middle, last: last); // named tuple elements in a literal |
它们也可以解构,这是一个非常好的新功能:
1 | (string first, string middle, string last) = LookupName(id1); // deconstructing declaration |
查看此链接以查看有关可以做什么的更多示例:)
你可以用三种不同的方法
1。参考/输出参数
使用REF:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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; } |
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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。结构/类
使用Stutt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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; } |
使用类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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; } |
三。元组
元组类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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元组
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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来做这个。您可以做的是拥有一个
1 2 3 4 | public int GetDay(DateTime date, out string name) { // ... } |
使用自定义类(或结构)
1 2 3 4 5 6 7 8 9 10 | public DayOfWeek GetDay(DateTime date) { // ... } public class DayOfWeek { public int Day { get; set; } public string Name { get; set; } } |
如果要返回多个值,可以返回包含要返回的值的类/结构,或者在参数上使用"out"关键字,如下所示:
1 2 3 | public void Foo(int input, out int output1, out string output2, out string errors) { // set out parameters inside function } |
上一张海报是对的。不能从C方法返回多个值。但是,您有几个选择:
- 返回包含多个成员的结构
- 返回类的实例
- 使用输出参数(使用out或ref关键字)
- 使用字典或键值对作为输出
这里的利弊往往很难弄清楚。如果返回结构,请确保它很小,因为结构是值类型并在堆栈上传递。如果您返回一个类的实例,这里有一些设计模式,您可能希望使用这些模式来避免引起问题-可以修改类的成员,因为C通过引用传递对象(您没有像在VB中那样使用ByVal)。
最后,您可以使用输出参数,但我会将其限制在只有两个(如3个或更少)参数的情况下使用——否则情况会变得难看和难以维护。此外,输出参数的使用可能是敏捷性的一个约束,因为每次需要向返回值添加内容时,方法签名都必须更改,而返回结构或类实例时,可以添加成员而不修改方法签名。
从体系结构的角度来看,我建议不要使用键值对或字典。我发现这种类型的编码需要消耗方法的代码中的"秘密知识"。它必须提前知道密钥将是什么以及值的含义,如果负责内部实现的开发人员改变了字典或kvp的创建方式,那么它很容易在整个应用程序中创建故障级联。
返回类实例或使用out参数。以下是out参数的示例:
1 2 3 4 5 | void mymethod(out int param1, out int param2) { param1 = 10; param2 = 20; } |
这样称呼它:
1 2 3 | int i, j; mymethod(out i, out j); // i will be 20 and j will be 10 |
不,不能从C(对于低于C 7的版本)中的函数返回多个值,至少不能像在Python中那样。
但是,有两种选择:
您可以返回一个类型为object的数组,其中包含您想要的多个值。
1 2 3 4 |
您可以使用
1 2 3 4 5 6 | private string DoSomething(out string outparam1, out int outparam2) { outparam1 = 'value2'; outparam2 = 3; return 'value1'; } |
有几种方法可以做到这一点。您可以使用
1 | int Foo(ref Bar bar) { } |
这将传递对函数的引用,从而允许函数修改调用代码堆栈中的对象。虽然这在技术上不是"返回"值,但它是一种让函数执行类似操作的方法。在上面的代码中,函数将返回一个
另一种类似的方法是使用
最后一种方法(大多数情况下最好)是创建一个封装两个值的类型,并允许函数返回:
1 2 3 4 5 6 7 | class FooBar { public int i { get; set; } public Bar b { get; set; } } FooBar Foo(Bar bar) { } |
最后一种方法简单易懂。
在C 4中,您将能够使用对元组的内置支持来轻松处理这一问题。
同时,有两种选择。
首先,可以使用ref或out参数为参数赋值,这些参数将被传递回调用例程。
这看起来像:
1 | void myFunction(ref int setMe, out int youMustSetMe); |
第二,您可以将返回值包装到一个结构或类中,并将它们作为该结构的成员传递回去。keyValuePair适用于2-对于2个以上的类或结构,需要自定义类或结构。
在C 7中有一个新的
1 2 3 4 | static (string foo, int bar) GetTuple() { return ("hello", 5); } |
您可以将此作为记录返回:
1 2 3 | var result = GetTuple(); var foo = result.foo // foo =="hello" |
还可以使用新的解构器语法:
1 2 | (string foo) = GetTuple(); // foo =="hello" |
但是,要小心串行化,所有这些都是语法上的糖分——在实际编译的代码中,这将是一个
因此,对于序列化,声明一个记录类并返回它。
C 7中的新功能还包括改进的
1 2 3 | if(int.TryParse("123", out int result)) { // Do something with result } |
但是,大多数情况下,您将在.NET自己的库中使用它,而不是在您自己的函数中使用它。
Some of these answers stated that use out parameter but I recommend
not using this due to they don’t work with async methods. See
this for more information.
其他的答案是使用tuple,我也建议使用c 7.0中引入的新特性。
1 2 3 4 5 6 7 8 | (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}."); |
更多信息可在这里找到。
你可以试试这个"keyValuePair"
1 2 3 4 5 6 7 8 9 | 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中不可能。
以下是基本的
1)使用"EDOCX1"〔3〕作为参数您也可以对4.0和次要版本使用"out"。
"out"示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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
*注:*
2)江户十一〔14〕号
元组示例:
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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); } } } |
产量
1 2 3 4 5 6 | perl java c# 1 2 3 |
注:tuple的使用在框架4.0及以上是有效的,
主要有两种方法。1。使用输出/参考参数2。返回对象数组
接受委托的方法可以向调用方提供多个值。这借用了我这里的答案,使用了哈达斯接受的答案中的一点。
1 2 3 4 5 | delegate void ValuesDelegate(int upVotes, int comments); void GetMultipleValues(ValuesDelegate callback) { callback(1, 2); } |
调用方提供lambda(或命名函数),IntelliSense通过从委托复制变量名来提供帮助。
1 2 3 4 | GetMultipleValues((upVotes, comments) => { Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments."); }); |
以OOP方式使用这样的类:
1 2 3 4 5 6 7 8 9 10 | class div { public int remainder; public int quotient(int dividend, int divisor) { remainder = ...; return ...; } } |
函数成员返回大多数调用者主要感兴趣的商。另外,它将剩余部分存储为一个数据成员,调用方随后可以很容易地访问它。
通过这种方式,您可以拥有许多额外的"返回值",如果您实现数据库或网络调用,这非常有用,在这种情况下可能需要大量的错误消息,但只有在发生错误时才有用。
我也在OP提到的C++问题中输入了这个解决方案。
1 2 3 4 5 6 7 | <--Return more statements like this you can --> public (int,string,etc) Sample( int a, int b) { //your code; return (a,b); } |
您可以接收类似的代码
1 | (c,d,etc) = Sample( 1,2); |
我希望它能奏效。
在本文中,您可以使用三个选项作为上述文章。
键值对是最快的方法。
出局是在第二个。
Tuple是最慢的。
不管怎样,这取决于什么是最适合您的场景。
您可以使用动态对象。我认为它的可读性比元组好。
1 2 3 4 5 6 7 8 9 10 11 12 | 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 ns):
1 2 3 4 | 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纳秒:
1 2 3 4 | 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)输出(1.64 ns)或参考4)创建自己的自定义类/结构
ns->纳秒
引用:多个返回值。
C的未来版本将包括命名的元组。看看这个Channel9演示会https://channel9.msdn.com/events/build/2016/b889
跳到13:00就可以了。这将允许以下内容:
1 2 3 4 5 6 7 | (int sum, int count) Tally(IEnumerable<int> list) { // calculate stuff here return (0,0) } int resultsum = Tally(numbers).sum |
(视频中不完整的示例)
也可以使用OperationResult
1 2 3 4 5 6 7 8 9 | 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; } |
你可以试试这个
1 2 3 4 |
现在,程序员需要时间和不可理解的方法。简单、有效、快速的解决方案:
1 2 3 4 |
在某个地方使用它;
1 2 3 | var results = SumAndSub(20, 5); int sum = results[0]; int sub = results[0]; |