Ok, this will be the last of the “easy” LINQ posts, meaning once we’re finished with this, we will be ready to get into the good stuff, like grouping, joining, etc. But no introduction to LINQ could be complete without a few words on projections.

LINQ can be used to query, filter, and older data. But it can also be used to transform input data into output data. What does that mean exactly? Well, it means that you can use LINQ to filter the input data using certain criteria and then use the LINQ to project the input data into another output sequence.

For example, we have seen in the previous post – LINQ queries and C# Methods – how LINQ can be used to filter the data and how that filter can be refined through various methods.

But what if we do not need all that data? And not only that but what if exposing some of that data to the front end could lead to some sensitive situations? Well, we would simply transform the data into an acceptable form – we would return a subset of it. We can do this directly using LINQ.

First, we’ll need a POCO class to hold our data:

public class Person
{
	public Person(string name, string email, int status)
	{
		Name = name;
		Email = email;
		Status = status;
	}

	public string Name { get; }

        public string Email { get; }

	public int Status { get; }
}

Now, here’s how we would filter that data and return only a subset of it, all practically in one line:

private Person[] persons = new[]
{
    new Person("Noel Pope", "a@google.net", 3),
    new Person("Justina Merritt", "nec.malesuada@icloud.edu", 1),
    new Person("Justina Florrick", "florrick@icloud.edu", 3),
    new Person("Justin Timberlake", "jtimberla.ke@icloud.edu", 1),
    new Person("Gabriel Dawson", "risus.quis.diam@icloud.com", 1),
    new Person("Caldwell Kirkland", "risus.donec@yahoo.com", 4),
    new Person("Tatum Pope", "at.iaculis@yahoo.org", 2),
};

var projection = persons
    .Where(p => p.Name.Contains("justin", StringComparison.InvariantCultureIgnoreCase))
    .Select(p => new
    {
        Name = p.Name,
        Status = p.Status
    });

foreach (var personInfo in projection)
{
    Console.WriteLine($"Name: {personInfo.Name}, Status: {personInfo.Status}.");
}

// Outputs:
// Name: Justina Merritt, Status: 1.
// Name: Justina Florrick, Status: 3.
// Name: Justin Timberlake, Status: 1.

Console.ReadKey();

As you can see above, we used Where() to filter the results and then Select() to have the query prepared to select only some properties of the Person. When the results are requested and the query is executed within the foreach loop, they are initialized with an anonymous type, meaning each “Person” element is then projected into the new anonymous type.

Naturally, we do not have to use anonymous types, we can use concrete classes:

public class PersonInfoViewModel
{
    public string Name { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
}

IEnumerable<PersonInfoViewModel> personInfos = from person in persons
                                                where person.Status == 1
                                                select new PersonInfoViewModel
                                                {
                                                    Email = person.Email,
                                                    Name = person.Name
                                                };

foreach (PersonInfoViewModel personInfo in personInfos)
{
    Console.WriteLine($"Name: {personInfo.Name}, E-Mail: {personInfo.Email}.");
}

//Name: Justina Merritt, E-Mail: nec.malesuada @icloud.edu.
//Name: Justin Timberlake, E-Mail: jtimberla.ke @icloud.edu.
//Name: Gabriel Dawson, E-Mail: risus.quis.diam @icloud.com.
Console.ReadKey();

Naturally, you might want to only have a calculated output result using input data, for example like this:

IEnumerable<string> output = persons.Select(p => $"Person {p.Name} with an E-Mail Address '{p.Email}' has a Status Value {p.Status}.");

foreach (string s in output)
{
    Console.WriteLine(s);
}

/*  OUTPUT:
    *  Person Noel Pope with an E-Mail Address 'a@google.net' has a Status Value 3.
    Person Justina Merritt with an E-Mail Address 'nec.malesuada@icloud.edu' has a Status Value 1.
    Person Justina Florrick with an E-Mail Address 'florrick@icloud.edu' has a Status Value 3.
    Person Justin Timberlake with an E-Mail Address 'jtimberla.ke@icloud.edu' has a Status Value 1.
    Person Gabriel Dawson with an E-Mail Address 'risus.quis.diam@icloud.com' has a Status Value 1.
    Person Caldwell Kirkland with an E-Mail Address 'risus.donec@yahoo.com' has a Status Value 4.
    Person Tatum Pope with an E-Mail Address 'at.iaculis@yahoo.org' has a Status Value 2.
*/

Console.ReadKey();

As you can see, you can do some really cool things with LINQ, including directly calling methods in query expressions and having the results directly calculated.

Hope you found something interesting in this post and hope to see you again here soon, as we are just starting with the wonder that is LINQ.