我如何返回C#中的函数的多个值?

我读了这个问题的C ++版本,但并没有真正理解它。

有人可以解释清楚,如果可以做,如何?

使用.NET 4.0 +的元组 :

例如:

public Tuple<int, int> GetMultipleValue() { return Tuple.Create(1,2); } 

你不能在C#中做到这一点。 你可以做的是有一个out参数或返回你自己的类(或结构,如果你想它是不可变的)。

使用out参数

 public int GetDay(DateTime date, out string name) { // ... } 

使用自定义类(或结构)

 public DayOfWeek GetDay(DateTime date) { // ... } public class DayOfWeek { public int Day { get; set; } public string Name { get; set; } } 

你可以使用三种不同的方式

1.参考/输出参数

使用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; } 

用掉:

 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:

 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; } 

使用类:

 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

 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语法

 (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}."); 

你也可以为元素提供名称(所以它们不是“Item1”,“Item2”等)。 你可以通过给签名或返回方法添加一个名字来实现:

 (string first, string middle, string last) LookupName(long id) // tuple elements have names 

要么

 return (first: first, middle: middle, last: last); // named tuple elements in a literal 

他们也可以被解构,这是一个相当不错的新function:

 (string first, string middle, string last) = LookupName(id1); // deconstructing declaration 

看看这个链接看到更多的例子可以做什么:)

如果你的意思是返回多个值,你可以返回一个包含你想返回值的类/结构,或者在你的参数中使用“out”关键字,如下所示:

 public void Foo(int input, out int output1, out string output2, out string errors) { // set out parameters inside function } 

以前的海报是正确的。 您不能从C#方法返回多个值。 但是,您有几个select:

  • 返回包含多个成员的结构
  • 返回一个类的实例
  • 使用输出参数(使用outref关键字)
  • 使用字典或键值对作为输出

这里的利弊往往很难弄清楚。 如果你返回一个结构,确保它很小,因为结构是值types并传递到堆栈上。 如果你返回一个类的实例,这里有一些devise模式,你可能想用来避免造成问题 – 类的成员可以被修改,因为C#通过引用传递对象(你没有像VB中那样的ByVal )。

最后,你可以使用输出参数,但是如果你只有几个参数(比如3或者更less),那么我会限制这个用法,否则事情就会变得很难维护。 另外,输出参数的使用可能会影响敏捷性,因为每次需要向返回值添加某些内容时,方法签名都必须更改,而返回结构体或类实例则可以在不修改方法签名的情况下添加成员。

从架构的angular度来看,我build议不要使用键值对或字典。 我发现这种编码风格需要消耗该方法的代码中的“秘密知识”。 它必须提前知道密钥将会是什么以及这些值是什么意思,如果内部实现的开发人员改变了字典或KVP的创build方式,那么很容易在整个应用程序中创build失败级联。

你要么返回一个类实例我们使用的参数。 这里是一个out参数的例子:

 void mymethod(out int param1, out int param2) { param1 = 10; param2 = 20; } 

像这样调用它:

 int i, j; mymethod(out i, out j); // i will be 20 and j will be 10 

有几种方法可以做到这一点。 你可以使用ref参数:

 int Foo(ref Bar bar) { } 

这通过对函数的引用,从而允许函数修改调用代码的堆栈中的对象。 虽然这在技术上不是一个“返回”的值,但它是一种让函数做类似的方法。 在上面的代码中,函数将返回一个int和(可能)修改bar

另一个类似的方法是使用out参数。 一个out参数与一个附加的编译器强制规则的ref参数相同。 这个规则是,如果你把一个outparameter passing给一个函数,这个函数在返回之前需要设置它的值。 除了这个规则外,一个out参数就像一个ref参数一样工作。

最后的方法(在大多数情况下是最好的)是创build一个封装两个值的types,并允许函数返回:

 class FooBar { public int i { get; set; } public Bar b { get; set; } } FooBar Foo(Bar bar) { } 

这最后的方法是更简单,更容易阅读和理解。

在C#4中,您将能够使用对元组的内置支持来轻松​​处理这个问题。

在此期间,有两种select。

首先,您可以使用ref或out参数为您的参数赋值,并返回到调用例程。

这看起来像:

 void myFunction(ref int setMe, out int youMustSetMe); 

其次,你可以将你的返回值包装到一个结构或类中,并把它们作为结构的成员传回去。 KeyValuePair适用于2 – 超过2你需要一个自定义的类或结构。

不,您不能从C#中的函数返回多个值(对于低于C#7的版本),至less不能以Python的方式返回。

但是,有几个select:

你可以用你想要的多个值返回一个types为object的数组。

 private object[] DoSomething() { return new [] { 'value1', 'value2', 3 }; } 

你可以使用out参数。

 private string DoSomething(out string outparam1, out int outparam2) { outparam1 = 'value2'; outparam2 = 3; return 'value1'; } 

你可以试试这个“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); 

输出:

输出:1,2

主要有两种方法。 1.使用out / ref参数2.返回一个对象数组

在C#7中有一个新的Tuple语法:

 static (string foo, int bar) GetTuple() { return ("hello", 5); } 

您可以将其作为logging返回:

 var result = GetTuple(); var foo = result.foo // foo == "hello" 

您也可以使用新的解构器语法:

 (string foo) = GetTuple(); // foo == "hello" 

但是,要注意序列化,所有这些都是语法糖 – 在实际编译的代码中,这将是一个Tupel<string, int> (按照接受的答案 ), Item1Item2代替foobar 。 这意味着序列化(或反序列化)将使用这些属性名称。

所以,为了序列化,声明一个logging类并返回。

在C#7中新增了一个改进的out参数语法。 现在你可以声明为inline,这在一些情况下更适合:

 if(int.TryParse("123", out int result)) { // Do something with result } 

但是,大多数情况下,您将在.NET自己的库中使用它,而不是在您自己的函数中。

类,结构,集合和数组可以包含多个值。 输出和参考参数也可以在一个函数中设置。 在dynamic语言和函数式语言中,可以通过元组返回多个值,但不能在C#中使用。

其中一些答案指出,使用了参数,但我build议不要使用这个,因为他们不使用asynchronous方法 。 看到这个更多的信息。

其他答案用Tuple表示,我也推荐使用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}."); 

更多信息可以在这里find。

这里是基本的Two方法:

1)使用' out '作为参数你也可以使用'out'作为4.0和minor版本。

“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(); } } } 

输出:

矩形区域是20

矩形的周长是18

* 注: *关键字描述了实际variables位置被复制到被调用方法的栈上的参数,这些地址可以被重写。 这意味着调用方法将访问更改的参数。

2) Tuple<T>

元组示例:

使用Tuple<T>返回多个DataType值

 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); } } } 

产量

 perl java c# 1 2 3 

注: 使用Tuple在Framework 4.0及以上版本中有效Tupletypes是一个class 。 它将被分配在内存中托pipe堆上的一个单独的位置。 一旦你创build了Tuple ,你就不能改变它的fields的值。 这使得Tuple更像一个struct

采取委托的方法可以为调用者提供多个值。 这从我的答案中借用,并从哈达斯接受的答案中稍微用一点。

 delegate void ValuesDelegate(int upVotes, int comments); void GetMultipleValues(ValuesDelegate callback) { callback(1, 2); } 

调用者提供一个lambda(或一个命名的函数)和intellisense通过从代理复制variables名称帮助。

 GetMultipleValues((upVotes, comments) => { Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments."); }); 

只需在OOP方式下使用这样的一个类:

 class div { public int remainder; public int quotient(int dividend, int divisor) { remainder = ...; return ...; } } 

函数成员函数返回大多数调用者主要感兴趣的商。另外,它将其余部分存储为数据成员,之后调用者可以轻松访问该成员。

这样,你可以有许多额外的“返回值”,如果你实现数据库或networking调用非常有用,可能需要大量的错误消息,但只有在发生错误的情况下。

我也在OP所指的C ++问题中input了这个解决scheme。

从这篇文章,你可以使用三个选项作为上面的post。

KeyValuePair是最快捷的方式。

在第二位。

元组是最慢的。

无论如何,这取决于你的情况最好的。

你可以使用一个dynamic的对象。 我认为它比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#将包括命名元组。 看看这个channel9会话的演示https://channel9.msdn.com/Events/Build/2016/B889

跳到13:00为元组的东西。 这将允许像这样的东西:

 (int sum, int count) Tally(IEnumerable<int> list) { // calculate stuff here return (0,0) } int resultsum = Tally(numbers).sum 

(来自video的不完整示例)

你可以试试这个

 public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } 

如何做到这一点:

1)KeyValuePair(最佳性能 – 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)元组 – 5.40纳秒:

  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)或ref 4)创build自己的自定义类/结构

ns – >纳秒

参考: 多个返回值 。

您也可以使用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; }