They are effectively the same generated IL with only minor emitted differences, However... they would likely be jitted and optimized to exactly the same instructions.
Given
private (String hello,string world) GetHelloAndWorldStrings()
{
return ("asdsd","sadfsdf");
}
...
public int Test1()
{
var asd = GetHelloAndWorldStrings();
if (asd.hello == "hello" && asd.world == "world")
return 1;
return 0;
}
public int Test2()
{
var (hello, world) = GetHelloAndWorldStrings();
if (hello == "hello" && world == "world")
return 1;
return 0;
}
Would basically be emitted as
public int Test1()
{
ValueTuple<string, string> helloAndWorldStrings = GetHelloAndWorldStrings();
if (helloAndWorldStrings.Item1 == "hello" && helloAndWorldStrings.Item2 == "world")
{
return 1;
}
return 0;
}
public int Test2()
{
ValueTuple<string, string> helloAndWorldStrings = GetHelloAndWorldStrings();
string item = helloAndWorldStrings.Item1;
string item2 = helloAndWorldStrings.Item2;
if (item == "hello" && item2 == "world")
{
return 1;
}
return 0;
}
You can check the IL out here
Here is an example of the JIT ASM in release
C.Test1()
L0000: push ebp
L0001: mov ebp, esp
L0003: push esi
L0004: mov ecx, [0x11198648]
L000a: mov esi, [0x1119864c]
L0010: mov edx, [0x11198650]
L0016: call System.String.Equals(System.String, System.String)
L001b: test eax, eax
L001d: je short L0038
L001f: mov edx, [0x11198654]
L0025: mov ecx, esi
L0027: call System.String.Equals(System.String, System.String)
L002c: test eax, eax
L002e: je short L0038
L0030: mov eax, 1
L0035: pop esi
L0036: pop ebp
L0037: ret
L0038: xor eax, eax
L003a: pop esi
L003b: pop ebp
L003c: ret
vs
C.Test2()
L0000: push ebp
L0001: mov ebp, esp
L0003: push esi
L0004: mov ecx, [0x11198648]
L000a: mov esi, [0x1119864c]
L0010: mov edx, [0x11198650]
L0016: call System.String.Equals(System.String, System.String)
L001b: test eax, eax
L001d: je short L0038
L001f: mov edx, [0x11198654]
L0025: mov ecx, esi
L0027: call System.String.Equals(System.String, System.String)
L002c: test eax, eax
L002e: je short L0038
L0030: mov eax, 1
L0035: pop esi
L0036: pop ebp
L0037: ret
L0038: xor eax, eax
L003a: pop esi
L003b: pop ebp
L003c: ret
In short, the net gain of worrying about this.. minus 5 minutes of your life you'll never get back
Item1
andItem2
. The names are there for readability only and they are only available at compile time. IL shows they useItem1
andItem2
regardless of what you've named them (ValueTuple is a struct with fields like any other structs) - e.g.valuetype [System.Runtime]System.ValueTuple``2<int32, int32>::Item1
– Utopiaif (helloAndWorld == ("hello","world"))
– Parkins