Thursday, February 13, 2014

Use of “Enumerable.Cast” and “Enumerable.OfType” in C#

There are situations where you have a collection that doesn’t support LINQ and you want to run some LINQ queries against a particular object or set of objects inside your  collection. Enumerable.Cast<TResult> and  Enumerable.OfType<TResult> Methods are real life savers in such scenarios In this post let’s see how we can use Enumerable.Cast<TResult> and  Enumerable.OfType<TResult> to make use of LINQ on a collection which doesn't support LINQ.

Let’s go by an example. I have created a console application. There I have the following class “Employee”.
public class Employee
{
    public int EmployeeId { get; set; }
    public string FullName { get; set; }
}
Then I have a ArrayList called oArrayList which will contain set of Employee objects. As you might already know ArrayList is a non-generic IEnumerable collection where you can store almost anything.
ArrayList oArrayList = new ArrayList()
{
    new Employee()
    {
        EmployeeId=1,FullName="Jaliya Udagedara"
    },
    new Employee()
    {
        EmployeeId=2,FullName="Martin Smith"
    }
};
Now let’s say I want to write a LINQ query against my ArrayList to find all the Employees where his/her FirstName starts with the letter “J”. Now let’s consider the following LINQ query.
var query = from e in oArrayList
            where e.FullName.StartsWith("J")
            select e;
This won’t even compile, I am getting the following error.  “Could not find an implementation of the query pattern for source type System.Collections.ArrayList.  Where not found.  Consider explicitly specifying the type of the range variable e”. That’s because of the following reason. ArrayList is a non-generic collection which implements IEnumerable and you don’t know the types of the elements which are in the ArrayList. So when you are writing a LINQ query and when you can't access types' properties, because you don't know what it is.

For that I can write the following LINQ query using query syntax.
var query = from Employee e in oArrayList
            where e.FullName.StartsWith("J")
            select e;
Here I have explicitly declared the type of the range variable (Employee is the type of range variable e) to reflect the specific type of the objects in my ArrayList. Here I have put the type as Employee, that's because I know by heart there can only be Employee objects in my ArrayList. If there were some other types other than the Employee, I will definitely be getting an exception of type InvalidCastException at the run time.

When I put the type of the range variable, it is equal as calling the Enumerable.Cast<TResult>.

Enumerable.Cast<TResult> Method

What Enumerable.Cast<TResult> does is, it casts the elements of an IEnumerable to the type specified in TResult. If an element cannot be cast to type TResult, this method will throw an InvalidCastException.

So if I write the following LINQ query, it would be same as the above query with explicitly declaring the type of the range variable.

Query Syntax
var query = from e in oArrayList.Cast<Employee>()
            where e.FullName.StartsWith("J")
            select e;
Method Syntax
var query = oArrayList.Cast<Employee>()
                .Where(e => e.FullName.StartsWith("J"));
Now if we want to filter out the objects that can be cast to type specified in TResult, we need to use Enumerable.OfType<TResult>.

Enumerable.OfType<TResult> Method

Enumerable.OfType<TResult> Method filters the elements of an IEnumerable based on a type specified in TResult.

Now let’s consider the following ArrayList which consists of two strings, two integers, three Lists of type string and two objects of type “Employee”.
ArrayList oArrayList = new ArrayList()
{
    "Jaliya",
    "Smith",
    10,
    20,
    new List<string>() { "VS", "SQL" },
    new List<string>() { "VS", "Windows Azure" },
    new List<string>() { "Apple", "Orange" },
    new Employee()
    {
        EmployeeId=1,FullName="Jaliya Udagedara"
    },
    new Employee()
    {
        EmployeeId=2,FullName="Martin Smith"
    }
};
Now let’s say I want to filter out the elements  in my ArrayList using Enumerable.OfType<TResult>  method when TResult is of following types. I am putting some conditions on my queries and I don’t think I should be describing them all. Here I will be writing the LINQ queries in both syntaxs (Query and Method Syntax).

TResult is String

Query Syntax
IEnumerable<string> query = from s in oArrayList.OfType<string>()
                            where s.StartsWith("J")
                            select s;
Method Syntax
IEnumerable<string> query = oArrayList.OfType<string>()
                                .Where(s => s.StartsWith("J"));

TResult is List<string>

Query Syntax
IEnumerable<List<string>> query = from l in oArrayList.OfType<List<string>>()
                                  where l.Contains("VS")
                                  select l;

Method Syntax
IEnumerable<List<string>> query = oArrayList.OfType<List<string>>().
                                        Where(l => l.Contains("VS"));

TResult is Employee

Query Syntax
IEnumerable<Employee> query = from e in oArrayList.OfType<Employee>()
                              where e.FullName.StartsWith("J")
                              select e;

Method Syntax
IEnumerable<Employee> query = oArrayList.OfType<Employee>()
                                .Where(e => e.FullName.StartsWith("J"));

Hope you all got a good understanding on  Enumerable.Cast<TResult> Method and  Enumerable.OfType<TResult> Method.

I am uploading the full sample code to my SkyDrive, enjoy.


Happy Coding.

Regards,
Jaliya

No comments:

Post a Comment