24

我可以将数组中的每个值分配给 C# 中一行中的单独变量吗?这是我想要的Ruby代码示例:

irb(main):001:0> str1, str2 = ["hey", "now"]
=> ["hey", "now"]
irb(main):002:0> str1
=> "hey"
irb(main):003:0> str2
=> "now"

我不确定我想要的在 C# 中是否可行。

编辑: 对于那些建议我只是将字符串“嘿”和“现在”分配给变量的人,这不是我想要的。想象一下:

irb(main):004:0> val1, val2 = get_two_values()
=> ["hey", "now"]
irb(main):005:0> val1
=> "hey"
irb(main):006:0> val2
=> "now"

现在,该方法get_two_values返回字符串“hey”和“now”的事实是任意的。事实上它可以返回任意两个值,它们甚至不必是字符串。

4

8 回答 8

17

这在 C# 中是不可能的。

我能想到的最接近的事情是在索引的同一行中使用初始化

strArr = new string[]{"foo","bar"};
string str1 = strArr[0], str2 = strArr[1];
于 2009-09-14T15:11:19.363 回答
14

更新:在 C#7 中,您可以使用元组轻松地一次分配多个变量。为了将数组元素分配给变量,您需要编写适当的Deconstruct()扩展方法:

使用元组的另一种方法是解构它们。解构声明是一种将元组(或其他值)拆分为其部分并将这些部分单独分配给新变量的语法:

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
WriteLine($"found {first} {last}.");

在解构声明中,您可以将 var 用于声明的各个变量:

(var first, var middle, var last) = LookupName(id1); // var inside

甚至在括号外放一个 var 作为缩写:

var (first, middle, last) = LookupName(id1); // var outside

您还可以使用解构赋值将现有变量解构:

(first, middle, last) = LookupName(id2); // deconstructing assignment

解构不仅仅适用于元组。任何类型都可以被解构,只要它具有以下形式的(实例或扩展)解构方法:

public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }

out 参数构成解构产生的值。

(为什么它使用 out 参数而不是返回一个元组?这样你就可以对不同数量的值进行多个重载)。

class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) { X = x; Y = y; }
    public void Deconstruct(out int x, out int y) { x = X; y = Y; }
}

(var myX, var myY) = GetPoint(); // calls Deconstruct(out myX, out myY);

以这种方式让构造函数和解构函数“对称”将是一种常见的模式。 https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/


老答案:

事实上,您可以通过使用这样的扩展方法在 C# 中实现类似的功能(注意:我没有包括检查参数是否有效):

public static void Match<T>(this IList<T> collection, Action<T,T> block)
{
    block(collection[0], collection[1]);
}
public static void Match<T>(this IList<T> collection, Action<T,T,T> block)
{
    block(collection[0], collection[1], collection[2]);
}
//...

你可以像这样使用它们:

new[] { "hey", "now" }.Match((str1, str2) =>
{
    Console.WriteLine(str1);
    Console.WriteLine(str2);
});

如果需要函数的返回值,则可以使用以下重载:

public static R Match<T,R>(this IList<T> collection, Func<T, T, R> block)
{
    return block(collection[0], collection[1]);
}

private string NewMethod1()
{   
    return new[] { "hey", "now" }.Match((str1, str2) =>
    {
        return str1 + str2;
    });
}

这样:

  • 您可以避免像 JaredPar 和其他人提出的解决方案那样重复数组名称;“变量”列表很容易阅读。

  • 您不必像 Daniel Earwicker 的解决方案那样显式声明变量类型。

缺点是你最终会得到额外的代码块,但我认为这是值得的。您可以使用代码片段以避免手动输入大括号等。

我知道这是一个 7 年前的问题,但不久前我需要这样一个解决方案 - 轻松为传递给方法的数组元素命名(不,使用类/结构而不是数组是不切实际的,因为对于相同的数组我可能在不同的方法中需要不同的元素名称),不幸的是我最终得到了这样的代码:

var A = points[0];
var A2 = points[1];
var B = points[2];
var C2 = points[3];
var C = points[4];

现在我可以写了(事实上,我现在已经重构了其中一种方法!):

points.Match((A, A2, B, C2, C) => {...});

我的解决方案类似于 F# 中的模式匹配,我受到这个答案的启发:https ://stackoverflow.com/a/2321922/6659843

于 2016-08-16T07:52:51.960 回答
4

现实世界的用例是提供一种从函数返回多个值的便捷方式。所以它是一个 Ruby 函数,它在数组中返回固定数量的值,调用者希望它们在两个单独的变量中。这是该功能最有意义的地方:

first_name, last_name = get_info() // always returns an array of length 2

要在 C# 中表达这一点,您可以out在方法定义中标记两个参数,然后返回void

public static void GetInfo(out string firstName, out string lastName)
{
    // assign to firstName and lastName, instead of trying to return them.
}

可以这么称呼它:

string firstName, lastName;
SomeClass.GetInfo(out firstName, out lastName);

这不是很好。希望未来的 C# 版本将允许这样做:

var firstName, lastName = SomeClass.GetInfo();

要启用此功能,该GetInfo方法将返回一个Tuple<string, string>. 这将是对语言的非破坏性更改,因为当前的合法用途var非常严格,因此上述“多重声明”语法尚无有效用途。

于 2010-03-27T21:49:23.560 回答
2

您可以在一行中做到这一点,但不能作为一个语句。

例如:

int str1 = "hey"; int str2 = "now";

Python 和 ruby​​ 支持你正在尝试做的任务;C# 没有。

于 2009-09-14T15:11:24.440 回答
2

您可以在 C# 中执行此操作

string str1 = "hey", str2 = "now";

或者你可以像这样花哨

        int x, y;
        int[] arr = new int[] { x = 1, y = 2 };
于 2010-07-24T14:38:47.000 回答
2

您现在可以在C# 7中使用命名元组。

{
  (string part1, string part2) = Deconstruct(new string[]{"hey","now"});
}

public (string, string) Deconstruct(string[] parts)
{
   return (parts[0], parts[1]);
}
于 2017-12-19T07:36:20.543 回答
1

我不确定我想要的在 C# 中是否可行。

它不是。

于 2009-09-14T15:11:25.573 回答
0

不,但您可以初始化一个字符串数组:

string[] strings = new string[] {"hey", "now"};

尽管这对您可能不太有用。坦率地说,将它们放在两条线上并不难:

string str1 = "hey";
string str2 = "now";
于 2009-09-14T15:13:33.167 回答