26

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.

6
  • 5
    Wow, ugly and confusing. Reminds me of my last date. Commented Sep 14, 2009 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. Commented Sep 14, 2009 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. Commented Sep 14, 2009 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. Commented Sep 14, 2009 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. Commented Feb 26, 2010 at 19:54

7 Answers 7

19

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];
Sign up to request clarification or add additional context in comments.

3 Comments

That's essentially what ruby does under the covers; the thing @Sarah wants to do is basically syntactic sugar.
I'd call it syntactic s-omething. Does Ruby hide the differences between memory allocation of primitives and reference types???
Ruby is a scripting language. There are no primitive types; they're all on the heap -- reference types.
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

Comments

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.

Comments

3

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

1 Comment

a lot more code than simple straight assignment. And not even generic
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.

Comments

1

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

It's not.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.