March 22, 2020

Tuple Compile Error - TupleElementNamesAttribute cannot be found

Problem:

The first time you use tuples in C# Projects, you may encountered this error:

Cannot define a class or member that utilizes tuples because the compiler required type 'System.Runtime.CompilerServices.TupleElementNamesAttribute' cannot be found.

Solution:

All you have to do is install System.ValueTuple nuget package.

From Package Manager Console, run this command:

Install-Package System.ValueTuple -Version 4.5.0

You may want to change the version if required.

Or from Manage NuGet Packages... tab, search for System.ValueTuple and Install.

March 12, 2020

C# - Return multiple values from a method

In this post, I will explain different ways to return multiple values from a method without using pre-defined custom struct or class definition.

  • Tuple

    First we can use Tuple return type, for example in below exmaple, Method1() is the method which will return mulitple values, and Method2() will call Method1() to receive the returned value.

    private Tuple<string, int> Method1(long id)
    {
     //get data from DB for given 'id'
     return Tuple.Create("Kamran", 25);
    }
    
    private void Method2()
    {
     var user = Method1(1);
    
     Console.WriteLine($"UserName = {user.Item1}, Age = {user.Item2}");
    }
    

    Tuples with two values have properties named Item1 and Item2. For more properties it will be name in same sequence Item3, Item4, Item5 and so on...

    In above exmaple, In Method2(), the user object(Tuple) has two properties, Item1 and Item2, which will have same data types respectively as defined in Method1()'s returned tuple. In this case, Item1 will be of string type, and Item2 will be of int type.

    Another way to consume/receive tuple value is to use deconstructor syntax. Method2() in above exmaple can also be written like this:

    private void Method2()
    {
     (string username, int age) = Method1(1);
    
     Console.WriteLine($"UserName = {username}, Age = {age}");
    }
    

    Here the returned value from tuple's items will be deconstructed to local variables username and age.

    Second way to create and return tuple is without Tuple keyword. You have to define types for each tuple item in parenthesis.

    private (string , int) Method1(long id) 
    {
     //get data from DB for given 'id'
     return ("Kamran", 25); 
    }
    

    As before, Tuple's items has items with names Item1, Item 2 and so on... If you want to explicitly define elements with your own name, you can use this syntax.

      
    private (string username, int age) Method1(long id)
    {
     return ("Kamran", 25);
    }
    

    Now you can access tuple's items by names.

    private void Method2()
    {
     var user = Method1(1);
    
     Console.WriteLine($"UserName = {user.username}, Age = {user.age}");
    }
    
  • Dynamic Type

    Second way to return multiple values by single method is to use dynamic type object.

    private static dynamic Method1(long id)
    {
     dynamic temp = new System.Dynamic.ExpandoObject();
     temp.Username = "Kamran";
     temp.Age = 25;
     
     return temp;
    }
    

    Consume dynamic type object returned from above method.

    private void Method2()
    {
     var user = Method1(1);
    
     Console.WriteLine($"UserName = {user.Username}, Age = {user.Age}");
    }
    

    Note that you will lose intellisense support and compile time type checking with dynamic type.

  • KeyValuePair

    Another way to return multiple values is to use KeyValuePair.

    private KeyValuePair Method1(long id)
    {
     return new KeyValuePair("Kamran", 25);
    }
    

    Consume KeyValuePair object returned from above method.

    private void Method2()
    {
     var user = Method1(1);
    
     Console.WriteLine($"UserName = {user.Key}, Age = {user.Value}");
    }
    

    Note that KeyValuePair object have only Key and Value parts, so you can use it to return two values maximum. If you want to return more than two values, then KeyValuePair is not a best fit.