39

How and "could be" organized return from the method which returns tuple type with the name of parameters, as an example

private static Tuple<string, string> methodTuple()
{
    return new {Name = "Nick", Age = "Twenty"}; /*exception because need to new Tuple<string, string>(){Item1 = "Nick", Item2 = "Twenty"}o*/
}

and call parameters like methodTuple.Name not like methodTuple.Item1....N

Is this possible or not?

UPD: I want to create object with named parameters without new named type.

Hulk
  • 97
  • 3
  • 16
AleksP
  • 1,244
  • 2
  • 12
  • 18

8 Answers8

43

In C# 7.0 (Visual Studio 2017) there is a new option to do that:

(string first, string middle, string last) LookupName(long id)
MichaelMocko
  • 5,466
  • 1
  • 21
  • 24
34

Starting C# v7.0, it is now possible to give custom name to tuple properties. Earlier they used to have default names like Item1, Item2 and so on. Let's look at few variations which is now possible:

  1. Naming the properties of Tuple Literals:

    var personDetails = (Name: "Foo", Age: 22, FavoriteFood: "Bar");
    Console.WriteLine($"Name - {personDetails.Name}, Age - {personDetails.Age}, Favorite Food - {personDetails.FavoriteFood}");
    

    The output on console:

    Name - Foo, Age - 22, Favorite Food - Bar

  2. Returning Tuple (having named properties) from a method:

    static void Main(string[] args)
    {
        var empInfo = GetEmpInfo();
        Console.WriteLine($"Employee Details: {empInfo.firstName}, {empInfo.lastName}, {empInfo.computerName}, {empInfo.Salary}");
    }
    
    static (string firstName, string lastName, string computerName, int Salary) GetEmpInfo()
    {
        //This is hardcoded just for the demonstration. Ideally this data might be coming from some DB or web service call
        return ("Foo", "Bar", "Foo-PC", 1000);
    }
    

    The output on console:

    Employee Details: Foo, Bar, Foo-PC, 1000

  3. Creating a list of Tuples having named properties:

    var tupleList = new List<(int Index, string Name)>
    {
        (1, "cow"),
        (5, "chickens"),
        (1, "airplane")
    };
    
    foreach (var tuple in tupleList)
        Console.WriteLine($"{tuple.Index} - {tuple.Name}");
    

    Output on console:

    1 - cow  
    5 - chickens  
    1 - airplane
    

Note: Code snippets in this post are using string interpolation feature of C# which was introduced in version 6 as detailed here.

RBT
  • 24,161
  • 21
  • 159
  • 240
  • 3
    install-package System.ValueTuple – OzBob Mar 14 '19 at 04:27
  • 1
    We are literally running away from classes - but I get it. If you need something once then this makes perfect sense. If I reuse the same structure 3 times (for me but 2 times for some people) then I make a class. – Andy Jun 25 '22 at 10:15
23

You need to declare a helper class to do so.

public class MyResult
{
    public string Name { get; set; }
    public string Age { get; set; }
}

What you're trying to return is an anonymous type. As the name suggests you don't know what its name is, so you can't declare your method to return it.

Anonymous Types (C# Programming Guide)

You cannot declare a field, a property, an event, or the return type of a method as having an anonymous type. Similarly, you cannot declare a formal parameter of a method, property, constructor, or indexer as having an anonymous type. To pass an anonymous type, or a collection that contains anonymous types, as an argument to a method, you can declare the parameter as type object. However, doing this defeats the purpose of strong typing. If you must store query results or pass them outside the method boundary, consider using an ordinary named struct or class instead of an anonymous type.

Update

C#7 introduces Tuple support built into the language and it comes with named tuples

(string name, int age) methodTuple()
{
    (...)
}

Read more on learn.microsoft.com: https://learn.microsoft.com/en-us/dotnet/articles/csharp/csharp-7#tuples

Red
  • 3,030
  • 3
  • 22
  • 39
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
  • 2
    Note that the type you defined here is mutable, not immutable, and hasn't overridden its equality semantics for value semantics, unlike `Tuple` or anonymous types. – Servy Jan 12 '15 at 18:49
  • 3
    I think this answer would be improved by moving the update to the top of the answer. – derekbaker783 Aug 31 '21 at 21:50
6

This is not possible with Tuple, no. You'll need to create your own new named type to do this.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • 7
    It's possible now in C# 7.0 – toddmo Mar 24 '17 at 18:34
  • @toddmo: What is the point of using a Tuple with named properties; over just using a normal class or anonymous type? Just asking because I can't think of a use case that isn't covered by the original possibilities. – Flater May 08 '17 at 09:42
  • @Flater, I encourage you to pose that itself as a question. Hopefully Eric, the head of the c# team, will give you their thinking. Here are the new capabilities: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/ – toddmo May 08 '17 at 17:22
  • 1
    @toddmo Anders Hejlsberg is the head of the C# team. If you mean Eric Lippert, he left the C# team a number of years back, and was never the head of the team. – Servy May 08 '17 at 17:28
  • 2
    @Flater they are great when you just need a couple properties grouped together - or a simple return type from a method where creating even a simple type seems like a chore. It's especially useful if it's a one off where a type would only ever be used once. It's sort of like an anonymous type that has named properties :-) Would be much more useful if you could declare an alias to a tuple to use in several places. – Simon_Weaver Oct 17 '19 at 04:22
4

Now you can do it with tuple Name in C#

For Lambda Expression:

private static (string Name, string Age) methodTuple() => ( "Nick", "Twenty" );

Or

private static (string Name, string Age) methodTuple()
{
    return ( "Nick", "Twenty" );
}

Do not use class type for Tuple. Use primitive type to set the name in Tuple.

2

I usually create a new type that derives from Tuple, and map your explicit properties to return the base class's ItemX properties. eg:

public class Person : Tuple<string, string>
{
    public Key(string name, string age) : base(name, age) { }

    public string Name => Item1;
    public string Age => Item2;
}
Tyson
  • 14,726
  • 6
  • 31
  • 43
  • Maybe I'm missing the point but why bother with a tuple and not just create a standard class? – Thierry Apr 30 '21 at 15:39
  • 1
    It implements `IComparable` and overrides `GetHashCode` so that equality is defined by the values in Item1 and Item2. Very useful if being used as a composite key in a dictionary (where my sample was derived from, notice I forgot to rename the class constructor). Although c#7 named tuples are a better solution nowadays. – Tyson May 07 '21 at 08:33
  • 2
    @Thierry tuples were created specifically so a special class did not need to be created just so a function can return 2+ values. The created class just becomes a DTO with no use really beyond the function – TSmith Feb 09 '22 at 19:51
0

Unfortunately, this is not possible using the "Tuple" type, as it is defined as "Item1...N" in MSDN. So this exception is valid.

This method can compile in 3 ways: 1.) Change return type to object - this will create an "anonymous" type, which you can then use later. It is not particularly useful if you want to access the "Name" or "Age" property later without some additional work. 2.) Change return type to dynamic - this will let you access the "Name" and "Age" property, but will make the entire program (just the DLL where this method is located really) slightly slower as the use of dynamic necessitates throwing out some strong typing. 3.) Create a class and use it as teh return type.

Sample code here:

private static object ObjectTuple()
        {
            return new { Name = "Nick", Age = "Twenty" };
        }

        private static dynamic DynamicTuple()
        {
            return new { Name = "Nick", Age = "Twenty" };
        }

        private static Temp TempTuple()
        {
            return new Temp{ Name = "Nick", Age = "Twenty" };
        }

        class Temp
        {
            public string Name { get; set; }
            public string Age { get; set; }
        }
Matt Clark
  • 1,171
  • 6
  • 12
0

As per me, when you want to return or get many things from a single method, better make its return type as CLASS but if you intend to use Tuple which itself is Class then for better naming this new class should inherit from Tuple. e.g. mentioned below.

 public CustomReturn ExecuteTask( int a, string b, bool c, object d )
        {
        // Calling constructor of CustomReturn Class to set and get values
          return new CustomReturn(a,b,c,d);
        }

        internal class CustomReturn 
        // for tuple inherit from Tuple<int,string,bool,object,double>
        { 
          //for tuple public int A{ get {this.Item1} private set;}

          public int A{get;private set;}
          public string B{get;private set;}
          public bool C{get;private set;}
          public object D{get;private set;}

          public CustomReturn (int a, string b, bool c, object d )
              // use this line for tuple ": base( obj, boolean )"
            {
              this.A = a;
              this.B = b;
              this.C = c;
              this.D = d;
            }

        }

    Main(args)
    {
      var result = ExecuteTask( 10, "s", true, "object" );
      // now if u have inherited Tuple for CustomReturn class then 

      // on doing result. you will get your custom name as A,B,C,D for //Item1,Item2,Item3,Item4 respectively also these Item1,Item2,Item3,Item4 will also be there.
    }
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
nissinku
  • 1
  • 1