118

I know it's possible to define aliases in C# with the using keyword.

e.g.

using ResponseKey = System.ValueTuple<System.Guid, string, string>;

However, is it possible to define one using the new syntax for value tuples?

using ResponseKey = (Guid venueId, string contentId, string answer);

This syntax does not appear to work. Should it?

Nick Randell
  • 17,805
  • 18
  • 59
  • 74
  • 1
    I don't know the answer, but it looks very like the same as "may I use var at module-level to define a variable?" – Mario Vernari Apr 03 '17 at 09:36
  • if it doesn't compile means it shouldn't work – Selman Genç Apr 03 '17 at 09:37
  • 4
    I don't know the answer, but it looks like it is better to create a class or struct for that purposes. Tuples are good, but please do not overuse it. – Yeldar Kurmangaliyev Apr 03 '17 at 09:41
  • 4
    Interesing comment @YeldarKurmangaliyev. The reason for using this is to not have to implement all the comparable interfaces to use as a simple key for an object. Yes, it's me being lazy, but it is also using the language features to their fullest. – Nick Randell Apr 03 '17 at 09:46
  • 3
    @NickRandell - most of the time you writing software for the people(other developers) - they will read your code. Having a class and properties with descriptive names - is more friendly/effective approach. Most of the times programmers spend on reading code(own and others) descriptive names and data structures will save their time – Fabio Apr 03 '17 at 09:56
  • The first thing I thought when seeing tuples. When it is a type, it should be able to behave like this, I thought. However, neither `using X = dynamic;` nor even `using X = int[];`. So, it doesn't have to work. – IS4 May 05 '17 at 20:40
  • Are you from a Python background, by any chance? – eddiewould Sep 13 '18 at 06:19
  • I'd like to see this work as well, it just seems natural. I can use `using Item = System.Tuple` but not `using Item = (int, int)`. The latter is just as much the "name" of a type as the former, at least to a layman. – Lee Jan 24 '19 at 01:07
  • @Fabio I'm 100% for descriptive code, but what would be missing here? You'd have all properties properly typed with descriptive names and if OP will have his wish even a name for the data structure. – Alex Aug 02 '20 at 16:01

1 Answers1

92

Updated. As of C# 10, you can define either a struct or class-based record to fulfill this requirement:

public record struct ResponseKey(Guid venueId, string contentId, string answer);
public record class ResponseKey(Guid venueId, string contentId, string answer);

Note that class is optional for the second definition.


This has been requested, and recorded in the Roslyn repo on Github. However it received a mixed reception there, and the proposed record types, would more than cover this requirement.

The issue was closed in the Roslyn repo but is now being tracked in the C# language repo.

David Arno
  • 42,717
  • 16
  • 86
  • 131
  • 1
    issue was closed and moved to https://github.com/dotnet/csharplang/issues/4284 – Troy Jul 09 '21 at 16:06
  • "[...] record types, would more than cover this requirement" except they are classes... – Noel Widmer Oct 04 '21 at 23:24
  • 1
    @NoelWidmer, records can be structs in C# 10. – David Arno Oct 05 '21 at 05:56
  • 1
    Worth noting another benefit: C# does automatic deconstruction for records, which makes them even more convenient (if you use deconstruction)! – void.pointer Jan 12 '22 at 19:10
  • one thing this loses is enumerability. with the `ITuple` interface I can enumerate the members of an arbitrary `ValueTuple`. I don't think there's a way to enumerate the members of a record (without going to reflection or something like that). (my goal is to have named members that are also enumerable but this is very difficult to achieve in a non-verbose way.) – Dave Cousineau Jul 16 '23 at 22:24
  • @DaveCousineau, [it's easy to have a record implement `ITuple` though](https://sharplab.io/#v2:EYLgtghglgdgNAExAagD4GIYFcA2OLA4CmABETAcQLABQtAAgAwn0CMAdAEpYwAuUYIuwDCAezAAHKMQBOAZSIyAblADGRAM4BuWrRlFVomQhIbeMrKt4lOACljWAHnBIOSATwCUJECQCSACpYEtQ0AN60AJD0AMwkosAAVga8APwkvAAWUBoA2m5QALokALwAfK6mAO5QvKqZJBE0kZHM5STOUZGspRXucF0A+r0ZmTKiVSQwRJN+MAhEjgDyWLxLAGacEDAA5kQAoo7qEvyiMLYAREswOO6u84skzABkJD0Q+iRKEDhQJutGGwXTxRAC+OmaUVi92sABlyDssiMAEwQ0FAA===). And having a generalized form of this would be relatively straightforward to implement with a source generator. – David Arno Jul 18 '23 at 12:07
  • @DavidArno hmm, that has to be implemented on each type, and has to be implemented with perfect accuracy each time to function correctly, and breaks as soon as you add a new member. what I did was use a record base type that adds new values to a static collection. you can then declare new static members in the inheritor that are named, and are also automatically enumerable from a static Values member. (requires the parent class to call the child class's static ctor with `RunClassConstructor`). – Dave Cousineau Jul 19 '23 at 02:39
  • (this is instead of using a value tuple of value tuples which also can work, but the type becomes cumbersome to express without a type alias) – Dave Cousineau Jul 19 '23 at 02:42