Assign values of array to separate variables in on

2019-01-19 10:52发布

Can I assign each value in an array to separate variables in one line in C#? Here's an example in Ruby code of what I want:

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

I'm not sure if what I'm wanting is possible in C#.

Edit: for those suggesting I just assign the strings "hey" and "now" to variables, that's not what I want. Imagine the following:

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

Now the fact that the method get_two_values returned strings "hey" and "now" is arbitrary. In fact it could return any two values, they don't even have to be strings.

8条回答
叼着烟拽天下
2楼-- · 2019-01-19 11:18

Update: In C#7 you can easily assign multiple variables at once using tuples. In order to assign array elements to variables, you'd need to write an appropriate Deconstruct() extension methods:

Another way to consume tuples is to deconstruct them. A deconstructing declaration is a syntax for splitting a tuple (or other value) into its parts and assigning those parts individually to fresh variables:

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

In a deconstructing declaration you can use var for the individual variables declared:

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

Or even put a single var outside of the parentheses as an abbreviation:

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

You can also deconstruct into existing variables with a deconstructing assignment:

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

Deconstruction is not just for tuples. Any type can be deconstructed, as long as it has an (instance or extension) deconstructor method of the form:

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

The out parameters constitute the values that result from the deconstruction.

(Why does it use out parameters instead of returning a tuple? That is so that you can have multiple overloads for different numbers of values).

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

It will be a common pattern to have constructors and deconstructors be “symmetric” in this way. https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/


Old answer:

In fact, you can achieve similar functionality in C# by using extension methods like this (note: I haven't include checking if arguments are valid):

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]);
}
//...

And you can use them like this:

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

In case a return value from a function is needed, the following overload would work:

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

In this way:

  • You avoid having to repeat array name like in solution proposed by JaredPar and others; the list of "variables" is easy to read.

  • You avoid having to explicitly declare variables types like in Daniel Earwicker's solution.

The disadvantage is that you end up with additional code block, but I think it's worth it. You can use code snippets in order to avoid typing braces etc. manually.

I know it's a 7 years old question, but not so long time ago I needed such a solution - easy giving names to array elements passed into the method (no, using classes/structs instead of arrays wasn't practical, because for same arrays I could need different element names in different methods) and unfortunately I ended up with code like this:

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

Now I could write (in fact, I've refactored one of those methods right now!):

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

My solution is similar to pattern matching in F# and I was inspired by this answer: https://stackoverflow.com/a/2321922/6659843

查看更多
该账号已被封号
3楼-- · 2019-01-19 11:21

No, but you can initialize an array of strings:

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

Although that's probably not too useful for you. Frankly its not hard to put them on two lines:

string str1 = "hey";
string str2 = "now";
查看更多
登录 后发表回答