There are two different "kinds" of tuples involved here: the .NET ValueTuple<...>
types, and C# tuple types. C# tuple types can have element names; ValueTuple<...>
types can't. (There's simply nowhere in the type system for that to live in a normal way.)
At execution time, a value is only aware of its .NET type. For example, if you use:
(string x, int y) tuple1 = ("hello", 10);
(string a, int b) tuple2 = ("hello", 10);
DoSomethingWithValue(tuple1);
DoSomethingWithValue(tuple2);
...
void DoSomethingWithValue(object value) { ... }
then DoSomethingWithValue
wouldn't be able to distinguish between the two tuple values at all. The information is only available at compile-time.
Information about element names for things like parameters and return types is propagated via attributes that the C# compiler consumes. So for example, a method declared like this:
public (string name, int score) GetFoo()
is compiled in IL as if it had been declared like this:
[TupleElementNames(new string[] { "name", "score" }]
public ValueTuple<string, int> GetFoo()
The C# language defines appropriate conversions between the .NET types and the C# tuple types to make it as seamless as possible.
In terms of how to use tuples, I'd use the C# tuple types as far as you can. Naming the tuple elements makes a huge difference in usability.