Blog from Saravanan Arumugam

Let us talk about Technologies

Use of Tuples


Tuple is a very useful class introduced in .Net framework 4.0. This paper talks about Tuples and their uses in different scenarios. But before explaining the Tuple, let me talk about some scenarios.

 

Scenario 1: Return multiple values from a function

Have you ever come across a scenario where you wanted to return multiple values from a called function?

Of course, out parameters and reference types in the argument are workarounds for it. But arguments are arguments. They are not completely the return values.

 

Scenario 2: Extend the scope of an anonymous object

Did you try to extend the scope of an anonymous type? For example, consider the following example.

try
{
    var fileData = (from line in File.ReadAllLines(file)
                    let columns = line.Split(',')
                    select new
                    {
                        Column1 = columns[0],
                        Column2 = columns[1],
                        Column3 = columns[2],
                        Column4 = columns[3]
                    }).ToList();
}
catch (Exception)
{
                
    throw;
}
 
foreach (var data in fileData) // File data is not available here.
{ }

In the example above, fileData is not available outside the try…catch block. If you want it outside the try block, you have to convert the anonymous type to a stable structure. The solution we can think of is create a Class with 4 properties. It may not make any sense to create a standard class for a temporary data.

 

Scenario 3: Pass multiple values through one parameter

In .Net framework, there are methods which would accept only one parameter to pass status values (For example using Thread.Start(Object)), but what would you do to send multiple values to it?

 

Tuple

Tuple is a single solution for all the above scenarios and more. Tuple has 8 forms,

1-tuple, or singleton Tuple<T1>
2-tuple, or pair Tuple<T1, T2>
3-tuple, or triple Tuple<T1, T2, T3>
4-tuple, or quadruple Tuple<T1, T2, T3, T4>
5-tuple, or quintuple Tuple<T1, T2, T3, T4, T5>
6-tuple, or sextuple Tuple<T1, T2, T3, T4, T5, T6>
7-tuple, or septuple Tuple<T1, T2, T3, T4, T5, T6, T7>
8-tuple, or octuple Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>

 

Usage

A tuple can be created with new operator as in other object. However using Tuple.Create  helper method, makes the creation of Tuple a lot more easier.

Tuple<string, int, float> car1Info = 

    new Tuple<string, int, float>(“Model1”, 28, 13200.58f);

 

Tuple<string, int, float> car2Info =

    Tuple.Create(“Model2”, 32, 14252.23f);

 

Solution to the scenarios

Here’s how the Tuple solves the above 3 scenarios stated above.

Scenario 1: Return multiple values from a function – Solution

I had to write a method that should process a file, and it has to return the following.

1. A Boolean to denote the success or failure of the process.

2. In case of failure, send out a custom message regarding the failure.

3. In case of any Exception, return the exception message.

For this I was left with two options. 1. Return one of these types, and pass the other two as out parameters. 2. Write a class containing these 3 items as public properties and return an object of this custom container class.

Tuple simplifies it as follows.

public Tuple<bool, string, Exception> ProcessFile(string file = null)
{}

 

Scenario 2: Extend the scope of an anonymous object – Solution

Define an array / list of tuples of whatever type you are about to create in the linq query. Create record of Tuple inside the linq type instead of anonymous one.

List<Tuple<long, DateTime, string, double>> records;
 
try
{
    records = (from record in rawFile.AsParallel()
                where record.Length == 4
                select Tuple.Create(
                    long.Parse(record[0]),
                    DateTime.Parse(record[1]),
                    record[2],
                    double.Parse(record[3])
                )).ToList();
}
catch (ArgumentNullException aEx)
{
    return Tuple.Create(false, 
        "There are Null values in record.", 
        (Exception)aEx);
}
catch (FormatException fEx)
{
    return Tuple.Create(false, 
        "Invalid record format.", 
        (Exception)fEx);
}
catch (OverflowException oEx)
{
    return Tuple.Create(false, 
        "Invalid Employee Id or duration format", 
        (Exception)oEx);
}
 
foreach (var record in records)
{
 
}

 

Scenario 3: Pass multiple values through one parameter – Solution

Following is a simple console app that reads a file asynchronously. The asynchronous method BeginRead takes 5 parameters. The last parameter is an object typed state indicator. This is the single parameter with which we can pass a value from the main method to the call back method (FileReadCompleted).

class Program

{

    static void Main(string[] args)

    {

        using (Stream stream =

            File.Open(@”C:\Temp\tempFile.txt”, FileMode.Open))

        {

            byte[] contents = new byte[200];

 

            IAsyncResult result =

                stream.BeginRead(contents, 0, 200,

                FileReadCompleted, stream);

 

            //Poll for the read operation’s completion

            while (!result.IsCompleted) ;

 

            Console.WriteLine(“File Read Started”);

 

            Console.WriteLine(“File Content:”);

            Console.WriteLine(Encoding.ASCII.GetString(contents));

        }

 

        Console.WriteLine(“Press any key to continue…”);

        Console.ReadKey();

    }

 

    public static void FileReadCompleted(IAsyncResult result)

    {

        Stream stream = (Stream)result.AsyncState;

        stream.EndRead(result);

    }

}

If at all we want to send more values to the callback method, Tuple will be a handy option. For example, I want the callback method to display to display the caller name (Main in our case). As a solution, I would like to send a string to the call back method and display it from within the callback.

class Program
{
    static void Main(string[] args)
    {
        using (Stream stream = 
            File.Open(@"C:\Temp\tempFile.txt", FileMode.Open))
        {
            byte[] contents = new byte[200];
 
            IAsyncResult result = stream.BeginRead(contents, 0, 200, 
                FileReadCompleted, 
                Tuple.Create(stream, "Main"));
 
            //Poll for the read operation's completion
            while (!result.IsCompleted) ;
 
            Console.WriteLine("File Read Started");
 
            Console.WriteLine("File Content:");
            Console.WriteLine(Encoding.ASCII.GetString(contents));
 
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }
 
    public static void FileReadCompleted(IAsyncResult result)
    {
        Tuple<Stream, string> stateValue = 
            (Tuple<Stream, string>)result.AsyncState;
 
        stateValue.Item1.EndRead(result);
 
        Console.WriteLine("File read completed. "
            + "This file read was initiated by {0}.",
            stateValue.Item2);
    }
}

 

References:

Tuple Class

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: