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

Ash*_*Ash 391 c# return

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

有人可以清楚地解释一下是否可以做到以及如何做?

Had*_*das 573

使用.NET 4.0 +的元组:

例如:

public Tuple<int, int> GetMultipleValue()
{
     return Tuple.Create(1,2);
}
Run Code Online (Sandbox Code Playgroud)

具有两个值的元组具有Item1Item2作为属性.

  • 如果代替Item1,Item2等等,可以使用命名输出值,这将是非常好的.[C#7可能会提供](http://stackoverflow.com/a/36436255/3375713). (7认同)
  • @Sнаđошƒаӽ 是绝对正确的,这有望在即将到来的 C# 7.0 中得到支持,使用如下语法:`public (int sum, int count) GetMultipleValues() { return (1, 2); } }` 这个例子取自[我们的文档主题例子](http://stackoverflow.com/documentation/c%23/1936/c-sharp-7-0-features/6329/language-support-for-元组)。 (2认同)
  • 如何捕获返回的元组并在调用方访问它们? (2认同)

Fra*_*ega 356

现在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
}
Run Code Online (Sandbox Code Playgroud)

然后可以像这样使用:

var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");
Run Code Online (Sandbox Code Playgroud)

您还可以为元素提供名称(因此它们不是"Item1","Item2"等).您可以通过为签名或返回方法添加名称来完成此操作:

(string first, string middle, string last) LookupName(long id) // tuple elements have names
Run Code Online (Sandbox Code Playgroud)

要么

return (first: first, middle: middle, last: last); // named tuple elements in a literal
Run Code Online (Sandbox Code Playgroud)

它们也可以解构,这是一个非常好的新功能:

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
Run Code Online (Sandbox Code Playgroud)

查看此链接以查看有关可执行操作的更多示例:)

  • 如果您的目标是.NET Framework 4.7或.NET Core 2.0之前的任何内容,则需要[安装NuGet包](/sf/answers/2686814511/). (8认同)

小智 177

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

1. ref/out参数

使用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;
}
Run Code Online (Sandbox Code Playgroud)

用完:

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;
}
Run Code Online (Sandbox Code Playgroud)

2. struct/class

使用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;
}
Run Code Online (Sandbox Code Playgroud)

使用课程:

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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 只是为了我自己的勇气,你会说这是最快和'最佳实践'? (3认同)
  • 我建议将 C# 7 元组作为首选选项。在我看来,这是迄今为止最好的一个。 (3认同)

Sam*_*uel 74

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

使用out参数
public int GetDay(DateTime date, out string name)
{
  // ...
}
Run Code Online (Sandbox Code Playgroud) 使用自定义类(或结构)
public DayOfWeek GetDay(DateTime date)
{
  // ...
}

public class DayOfWeek
{
  public int Day { get; set; }
  public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,另一种方法是使用struct而不是类作为返回类型.如果返回值是无状态和瞬态的,那么struct是更好的选择. (24认同)
  • 现在可以在C#7中使用:(int,int)Method(){return(1,2); } (5认同)
  • 答案需要更新,最近版本的c#已经出现问题.如果更新,将更改downvote to upvote. (4认同)

Chr*_*ett 38

如果您的意思是返回多个值,您可以返回包含要返回的值的类/结构,或者在参数上使用"out"关键字,如下所示:

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

  • 我认为使用"out"或"ref"并不好 - 因为它可以完全由你自己的类类型的返回值代替.你看,如果使用"ref",如何分配这些参数?(这取决于如何编码内部).如果在函数体中,作者使用"ref"向参数"newed"了一个实例,这意味着你可以在那里传递一个"可为空"的值.其他的不是.所以这有点野蛮.我们有更好的方法(1.归还你自己的班级,2.Turple). (2认同)

Kev*_*man 33

以前的海报是对的.您无法从C#方法返回多个值.但是,您有两个选择:

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

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

最后你可以使用输出参数,但是当你只有一对(比如3个或更少)的参数时,我会限制它的使用情况 - 否则事情变得难看并且难以维护.此外,输出参数的使用可能会影响敏捷性,因为每次需要向返回值添加内容时,方法签名都必须更改,而返回结构或类实例则可以在不修改方法签名的情况下添加成员.

从架构的角度来看,我建议不要使用键值对或字典.我发现这种编码风格在代码中需要"秘密知识"才能使用该方法.它必须提前知道密钥将是什么以及值意味着什么,如果开发内部实现的开发人员改变了字典或KVP的创建方式,它可以轻松地在整个应用程序中创建故障级联.


Kel*_*tex 19

您要么返回类实例,要么使用out参数.以下是输出参数的示例:

void mymethod(out int param1, out int param2)
{
    param1 = 10;
    param2 = 20;
}
Run Code Online (Sandbox Code Playgroud)

像这样称呼它:

int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10
Run Code Online (Sandbox Code Playgroud)

  • 请记住,虽然这只是因为你可以,但并不意味着你应该这样做.在大多数情况下,这被广泛认为是.Net中的一种不良做法. (3认同)
  • 你能详细说明为什么这是一个不好的做法? (3认同)

dus*_*ell 11

不,你不能从C#中的函数返回多个值(对于低于C#7的版本),至少不是你在Python中的方式.

但是,有几种选择:

您可以返回一个类型为object的数组,其中包含您想要的多个值.

private object[] DoSomething()
{
    return new [] { 'value1', 'value2', 3 };
}
Run Code Online (Sandbox Code Playgroud)

您可以使用out参数.

private string DoSomething(out string outparam1, out int outparam2)
{
    outparam1 = 'value2';
    outparam2 = 3;
    return 'value1';
}
Run Code Online (Sandbox Code Playgroud)


And*_*are 11

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

int Foo(ref Bar bar) { }
Run Code Online (Sandbox Code Playgroud)

这传递了对函数的引用,从而允许函数修改调用代码堆栈中的对象.虽然这在技术上不是"返回"值,但它是一种使函数执行类似操作的方法.在上面的代码中,函数将返回an int和(可能)修改bar.

另一种类似的方法是使用out参数.参数与具有附加编译器强制规则的out参数相同ref.此规则是,如果将out参数传递给函数,则需要该函数在返回之前设置其值.除了该规则,out参数就像ref参数一样工作.

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

class FooBar 
{
    public int i { get; set; }
    public Bar b { get; set; }
}

FooBar Foo(Bar bar) { }
Run Code Online (Sandbox Code Playgroud)

最后的方法更简单,更易于阅读和理解.


nzr*_*tmn 11

有很多方法;但是,如果您不想创建新的Object或结构或类似的东西,可以在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");

    }
Run Code Online (Sandbox Code Playgroud)


Ree*_*sey 10

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

与此同时,有两种选择.

首先,您可以使用ref或out参数为参数赋值,这些值将传递回调用例程.

这看起来像:

void myFunction(ref int setMe, out int youMustSetMe);
Run Code Online (Sandbox Code Playgroud)

其次,您可以将返回值包装到结构或类中,并将它们作为该结构的成员传回.KeyValuePair适用于2 - 对于2个以上,您需要一个自定义类或结构.


Lui*_*jon 10

其中一些答案表明使用out参数,但我建议不要使用它,因为它们不能与异步方法一起使用.有关更多信息,请参阅

其他答案使用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}.");
Run Code Online (Sandbox Code Playgroud)

更多信息可以在这里找到.


sta*_*rsp 10

当您的方法是异步的并且您想要返回多个属性时。你必须这样做:

public async Task<(int, int)> GetMultipleValues(){
   return (1,2);
}
Run Code Online (Sandbox Code Playgroud)


小智 9

<--Return more statements like this you can --> 

public (int,string,etc) Sample( int a, int b)  
{
    //your code;
    return (a,b);  
}
Run Code Online (Sandbox Code Playgroud)

您可以收到类似的代码

(c,d,etc) = Sample( 1,2);
Run Code Online (Sandbox Code Playgroud)

我希望它有效。

  • 这个答案很完美,完全满足了需要。真的很有帮助,谢谢! (3认同)

Kei*_*ith 8

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

static (string foo, int bar) GetTuple()
{
    return ("hello", 5);
}
Run Code Online (Sandbox Code Playgroud)

您可以将此作为记录返回:

var result = GetTuple();
var foo = result.foo
// foo == "hello"
Run Code Online (Sandbox Code Playgroud)

您还可以使用新的解构函数语法:

(string foo) = GetTuple();
// foo == "hello"
Run Code Online (Sandbox Code Playgroud)

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

因此,对于序列化声明一个记录类并返回它.

C#7中的新功能还包括out参数的改进语法.您现在可以声明out内联,这在某些情况下更适合:

if(int.TryParse("123", out int result)) {
    // Do something with result
}
Run Code Online (Sandbox Code Playgroud)

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


Rik*_*tel 7

你可以尝试这个"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);
Run Code Online (Sandbox Code Playgroud)

输出:

输出:1,2


Jos*_*lio 5

类,结构,集合和数组可以包含多个值.输出和参考参数也可以在函数中设置.通过元组在动态和函数语言中返回多个值,但在C#中则不行.