25

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.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Sarah Vessels
  • 30,930
  • 33
  • 155
  • 222
  • 4
    Wow, ugly and confusing. Reminds me of my last date. –  Sep 14 '09 at 15:12
  • 3
    @Will: Really? I think it's nice and succinct, while still being clear and readable. I rather like the feature in python and use it frequently. – Randolpho Sep 14 '09 at 15:16
  • 1
    From a C# perspective, definitely. It looks like you're assigning a reference to a single array to two different varaibles... like str1 = new string[] {"one","two"}; str2 = str1; So its immediately confusing to C# developers. The ugly bit was just so I could fit in the joke. –  Sep 14 '09 at 15:19
  • 5
    Perhaps if C# is your only language, then yes, I suppose it looks kinda ugly. Maybe you should consider broadening your horizons? Anyway, although I've never developed in ruby, I've done a ton in python, so that assignment is not new to me at all. It looks like a simple tuple creation and an unpack (also called a tuple assignment). Although Ruby apparently uses brackets [] rather than parens () like python, it's otherwise syntactically identical. Based on comments from @Sarah, I expect it functions identically. – Randolpho Sep 14 '09 at 18:37
  • I think Will is referring to the command line portion of the example. Not having done Ruby I did a double take myself. The assignment itself is succinct, clear, and readable. – pdavis Feb 26 '10 at 19:54
  • https://stackoverflow.com/a/47816647/1225421 – Alex P. Mar 31 '23 at 18:44

7 Answers7

18

This is not possible in C#.

The closest thing I can think of is to use initialization in the same line with indexs

strArr = new string[]{"foo","bar"};
string str1 = strArr[0], str2 = strArr[1];
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    That's essentially what ruby does under the covers; the thing @Sarah wants to do is basically syntactic sugar. – Randolpho Sep 14 '09 at 15:13
  • I'd call it syntactic s-omething. Does Ruby hide the differences between memory allocation of primitives and reference types??? –  Sep 14 '09 at 15:20
  • 1
    Ruby is a scripting language. There are no primitive types; they're all on the heap -- reference types. – Randolpho Sep 14 '09 at 18:33
15

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

Community
  • 1
  • 1
user1414213562
  • 5,583
  • 1
  • 14
  • 10
4

The real-world use case for this is providing a convenient way to return multiple values from a function. So it is a Ruby function that returns a fixed number of values in the array, and the caller wants them in two separate variables. This is where the feature makes most sense:

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

To express this in C# you would mark the two parameters with out in the method definition, and return void:

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

And so to call it:

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

It's not so nice. Hopefully some future version of C# will allow this:

var firstName, lastName = SomeClass.GetInfo();

To enable this, the GetInfo method would return a Tuple<string, string>. This would be a non-breaking change to the language as the current legal uses of var are very restrictive so there is no valid use yet for the above "multiple declaration" syntax.

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
2

You can do it in one line, but not as one statement.

For example:

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

Python and ruby support the assignment you're trying to do; C# does not.

Randolpho
  • 55,384
  • 17
  • 145
  • 179
2

You can use named tuples with C# 7 now.

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

public (string, string) Deconstruct(string[] parts)
{
   return (parts[0], parts[1]);
}
Illuminati
  • 4,539
  • 2
  • 35
  • 55
1

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

It's not.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
0

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";
Ron Warholic
  • 9,994
  • 31
  • 47