Answers:
在C#7及更高版本中,请参见此答案。
在以前的版本中,可以使用.NET 4.0+的Tuple:
例如:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
具有两个值的元组具有Item1
和Item2
属性。
public (int sum, int count) GetMultipleValues() { return (1, 2); }
此功能:此示例摘自此文档主题示例。
现在已经发布了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
它们也可以被解构,这是一个非常不错的新功能:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
查看此链接,以查看有关可以做什么的更多示例:)
您可以使用三种不同的方式
1.参考/输出参数
使用参考:
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 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.元组
元组类
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元组
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#中执行此操作。您可以做的是拥有一个out
参数或返回自己的类(如果希望它是不可变的,则返回struct)。
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; }
}
async
方法是不可能的。Tuple
是要走的路。(out
尽管我在同步操作中使用参数;但在那些情况下它们确实很有用。)
如果要返回多个值,则可以返回包含要返回的值的类/结构,也可以在参数上使用“ out”关键字,如下所示:
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
以前的海报是正确的。您不能从C#方法返回多个值。但是,您确实有两种选择:
这里的优缺点通常很难弄清楚。如果返回结构,请确保它很小,因为结构是值类型并在堆栈上传递。如果返回类的实例,则可能需要使用一些设计模式来避免引起问题-可以修改类的成员,因为C#通过引用传递对象(您不像在VB中那样具有ByVal )。
最终,您可以使用输出参数,但是当您只有几个参数(例如3个或更少)时,我将把它限制在方案中使用-否则情况将变得难看且难以维护。另外,使用输出参数可能会抑制敏捷性,因为每次需要在返回值中添加某些内容时,方法签名都将不得不更改,而返回结构或类实例时,可以在不修改方法签名的情况下添加成员。
从体系结构的角度,我建议不要使用键值对或字典。我发现这种编码风格需要使用该方法的代码中的“秘密知识”。它必须提前知道键将是什么以及键的含义是什么,以及如果内部实施工作的开发人员更改了字典或KVP的创建方式,则它很容易在整个应用程序中创建故障级联。
Exception
如果要返回的第二个值与第一个值是不相交的,则也可以抛出一个:例如,当您要返回一种成功值或一种不成功值时。
您可以返回类实例,也可以使用out参数。这是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
有很多方法;但是,如果您不想创建新的对象或结构或类似的东西,可以在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");
}
在C#7中,有一个新Tuple
语法:
static (string foo, int bar) GetTuple()
{
return ("hello", 5);
}
您可以将其作为记录返回:
var result = GetTuple();
var foo = result.foo
// foo == "hello"
您还可以使用新的析构函数语法:
(string foo) = GetTuple();
// foo == "hello"
小心系列化然而,这一切都是语法糖-在实际的编译代码,这将是一个Tuple<string, int>
(如依照公认的答案)与Item1
和Item2
而不是foo
和bar
。这意味着序列化(或反序列化)将改为使用这些属性名称。
因此,要进行序列化,请声明一个记录类,然后将其返回。
C#7中的另一个新功能是改进了out
参数语法。现在out
,您可以声明内联,它更适合某些情况:
if(int.TryParse("123", out int result)) {
// Do something with result
}
但是,大多数情况下,您将在.NET自己的库中使用它,而不是在自己的函数中使用它。
一些答案建议使用参数,但是我建议不要使用它,因为它们不适用于异步方法。请参阅 此以获取更多信息。
其他答案使用Tuple进行了说明,我也建议使用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}.");
可以在此处找到更多信息。
有几种方法可以做到这一点。您可以使用ref
参数:
int Foo(ref Bar bar) { }
这将传递对函数的引用,从而允许函数修改调用代码堆栈中的对象。尽管从技术上讲这不是“返回”值,但它是一种使函数执行类似操作的方法。在上面的代码中,该函数将返回an int
和(可能)Modify bar
。
另一种类似的方法是使用out
参数。参数与带有附加的编译器强制规则的out
参数相同ref
。此规则是,如果您将out
参数传递给函数,则要求该函数在返回之前设置其值。除了该规则之外,out
参数的工作原理与ref
参数相同。
最终的方法(在大多数情况下是最好的方法)是创建一个封装两个值的类型,并允许函数返回该值:
class FooBar
{
public int i { get; set; }
public Bar b { get; set; }
}
FooBar Foo(Bar bar) { }
最后一种方法更简单,更易于阅读和理解。
不,您不能从C#中的函数返回多个值(对于低于C#7的版本),至少不能以在Python中实现的方式返回。
但是,有两种选择:
您可以返回类型对象数组,其中包含您想要的多个值。
private object[] DoSomething()
{
return new [] { 'value1', 'value2', 3 };
}
您可以使用out
参数。
private string DoSomething(out string outparam1, out int outparam2)
{
outparam1 = 'value2';
outparam2 = 3;
return 'value1';
}
类,结构,集合和数组可以包含多个值。输出和参考参数也可以在功能中设置。通过元组可以在动态和功能语言中返回多个值,但在C#中则不能。
基本Two
方法如下:
1)使用' out
'作为参数
您也可以将'out'用于4.0和次要版本。
'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
* 注意: * out
-keyword描述参数,这些参数的实际变量位置被复制到被调用方法的堆栈中,这些位置可以被重写。这意味着调用方法将访问更改的参数。
2) Tuple<T>
元组示例:
使用以下方法返回多个DataType值 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);
}
}
}
输出量
perl
java
c#
1
2
3
注意: 使用Tuple在Framework 4.0及更高版本中有效。Tuple
类型是class
。它将被分配在内存中托管堆上的单独位置。创建后Tuple
,您将无法更改其值fields
。这使得它Tuple
更像一个struct
。
接受委托的方法可以为调用者提供多个值。这借鉴了我在这里的答案,并使用了哈达斯接受的答案。
delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
callback(1, 2);
}
调用者提供一个lambda(或命名函数),并且intellisense通过从委托中复制变量名称来提供帮助。
GetMultipleValues((upVotes, comments) =>
{
Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
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
(视频中的不完整示例)
您可以使用动态对象。我认为它比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;
}
方式:
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 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)输出(1.64 ns)或参考4)创建自己的自定义类/结构
ns->纳秒
参考:多重返回值。
你可以试试这个
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
不必显式创建新的string[]
?
专门针对数组类型的快速答案返回:
private int[] SumAndSub(int A, int B)
{
return new[] { A + B, A - B };
}
使用:
var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[1];