Query NonGeneric Types using LINQ in C# and VB.NET

Posted by: Suprotim Agarwal , on 10/5/2008, in Category LINQ
Views: 30549
Abstract: LINQ can be used to query on objects that are generic collections and implement the generic IEnumerable interface. However nongeneric collections like the ArrayList do not implement the 'generic' IEnumerable interface. In this article we will see how to use LINQ to query nongeneric collections like the ArrayList.
Query NonGeneric Types using LINQ in C# and VB.NET 
 
Generics was introduced in .NET Framework 2.0. Before that the System.Collections namespace consisted of collections that could store objects. After Generics became available in .NET 2.0, a lot of collection classes adopted Generics and implemented the IEnumerable<T> interface. However there were other nongeneric types that did not support the generic versions of IEnumerable (however they did support the nongeneric version of IEnumerable).
LINQ can be used to query on objects that are generic collections and implement the IEnumerable<T> interface. However nongeneric collections like the ArrayList do not implement the IEnumerable<T> interface. Let us see what happens when we query nongeneric collections using LINQ.
C#
public class Cars
{
public string CarMake { get;set;}
public string CarModel { get; set; }
public int Year { get; set; }
}
 
 
class Program
{
static void Main(string[] args)
{
    ArrayList carList = new ArrayList();
    carList.Add(new Cars
        {
            CarMake="BMW", CarModel="BMW Art", Year=1978
        });
    carList.Add(new Cars
        {
            CarMake = "BMW", CarModel = "Coupe", Year = 1982
        });
    carList.Add(new Cars
        {
            CarMake = "Renault", CarModel = "Alpine", Year = 1972
        });
    carList.Add(new Cars
        {
            CarMake = "Porsche", CarModel = "Maisto", Year = 1976
        });
 
    var carQuery = from car in carList
                   where car.CarMake == "BMW"
                   select car;
}
VB.NET
Public Class Cars
Private privateCarMake As String
Public Property CarMake() As String
      Get
            Return privateCarMake
      End Get
      Set(ByVal value As String)
            privateCarMake = value
      End Set
End Property
Private privateCarModel As String
Public Property CarModel() As String
      Get
            Return privateCarModel
      End Get
      Set(ByVal value As String)
            privateCarModel = value
      End Set
End Property
Private privateYear As Integer
Public Property Year() As Integer
      Get
            Return privateYear
      End Get
      Set(ByVal value As Integer)
            privateYear = value
      End Set
End Property
End Class
 
 
Friend Class Program
Shared Sub Main(ByVal args() As String)
      Dim carList As New ArrayList()
      carList.Add(New Cars With {.CarMake="BMW", .CarModel="BMW Art", .Year=1978})
      carList.Add(New Cars With {.CarMake = "BMW", .CarModel = "Coupe", .Year = 1982})
      carList.Add(New Cars With {.CarMake = "Renault", .CarModel = "Alpine", .Year = 1972})
      carList.Add(New Cars With {.CarMake = "Porsche", .CarModel = "Maisto", .Year = 1976})
 
      Dim carQuery = _
            From car In carList _
            Where car.CarMake = "BMW" _
            Select car
End Sub
In the example shown above, we have declared and populated an ArrayList with the Cars objects. We query the ArrayList using LINQ, just as we would have queried a collection implementing the IEnumerable<T> like the Array. What do you think would be the result?
Well the code shown above will never compile at the first place. The reason being that ArrayList does not inherit from IEnumerable<T> and hence LINQ cannot query such collections. So does that conclude that we cannot use LINQ against nongeneric collections like ArrayList? What about those class libraries that contain methods returning ArrayList? Do we scrap those methods or replace them with methods returning Generic Collections? Well without dramatizing this further, the answer is that there are ‘tricks’ using which we can query nongeneric collections using LINQ. Let us see three different ways to do so:
Method 1: By specifying the type of the variable to reflect the specific type of the objects in the collection:
By explicitly declaring the type of the variable while querying, you can cast each item in the ArrayList to reflect the specific type, in our case Cars.
C#
    var cc = from Cars car in carList
             where car.CarMake == "BMW"
             select car;
VB.NET
      Dim cc = _
            From car As Cars In carList _
            Where car.CarMake = "BMW" _
            Select car
Observe how we are casting the ‘car’ variable to ‘Cars’.
Method 2: By using the ‘Cast’ operator.
The ‘Cast’ operator takes a nongeneric collection (that implements IEnumerable) and returns an IEnumerable<T>. Once we get an IEnumerable<T>, we can then query the collection using LINQ.
C#
      
    var cc1 = from car in carList.Cast<Cars>()
              where car.CarMake == "BMW"
              select car;
 
VB.NET
      Dim cc1 = _
            From car In carList.Cast(Of Cars)() _
            Where car.CarMake = "BMW" _
            Select car
Note: The approach we followed in Method 1 is equivalent to calling Cast.
Method 3: Instead of Cast, you can also use the OfType operator.
The ‘OfType’ operator filters the elements of an IEnumerable based on a specified type. So if you have different  types in your ArrayList, you get back only the type you have queried for.
C#
    var cc2 = from car in carList.OfType<Cars>()
              where car.CarMake == "BMW"
              select car;
VB.NET
      Dim cc2 = _
            From car In carList.OfType(Of Cars)() _
            Where car.CarMake = "BMW" _
            Select car
The entire source code with the 3 different methods would look as follows:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
 
namespace QueryArraylistWithLINQ
{
public class Cars
{
public string CarMake { get;set;}
public string CarModel { get; set; }
public int Year { get; set; }
}
 
 
class Program
{
    static void Main(string[] args)
    {
        ArrayList carList = new ArrayList();
        carList.Add(new Cars
            {
                CarMake = "BMW",
                CarModel = "BMW Art",
                Year = 1978
            });
        carList.Add(new Cars
            {
                CarMake = "BMW",
                CarModel = "Coupe",
                Year = 1982
            });
        carList.Add(new Cars
            {
                CarMake = "Renault",
                CarModel = "Alpine",
                Year = 1972
            });
        carList.Add(new Cars
            {
                CarMake = "Porsche",
                CarModel = "Maisto",
                Year = 1976
            });
 
 
        var cc = from Cars car in carList
                 where car.CarMake == "BMW"
                 select car;
 
        var cc1 = from car in carList.Cast<Cars>()
              where car.CarMake == "BMW"
              select car;
 
        var cc2 = from car in carList.OfType<Cars>()
              where car.CarMake == "BMW"
              select car;
 
 
        foreach (Cars c in cc1)
            Console.WriteLine(c.CarMake + "-" + c.CarModel);
 
        Console.ReadLine();
    }
}
}
 
VB.NET
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Collections
 
Namespace QueryArraylistWithLINQ
Public Class Cars
Private privateCarMake As String
Public Property CarMake() As String
      Get
            Return privateCarMake
      End Get
      Set(ByVal value As String)
            privateCarMake = value
      End Set
End Property
Private privateCarModel As String
Public Property CarModel() As String
      Get
            Return privateCarModel
      End Get
      Set(ByVal value As String)
            privateCarModel = value
      End Set
End Property
Private privateYear As Integer
Public Property Year() As Integer
      Get
            Return privateYear
      End Get
      Set(ByVal value As Integer)
            privateYear = value
      End Set
End Property
End Class
 
 
Friend Class Program
      Shared Sub Main(ByVal args() As String)
            Dim carList As New ArrayList()
            carList.Add(New Cars With {.CarMake = "BMW", .CarModel = "BMW Art", .Year = 1978})
            carList.Add(New Cars With {.CarMake = "BMW", .CarModel = "Coupe", .Year = 1982})
            carList.Add(New Cars With {.CarMake = "Renault", .CarModel = "Alpine", .Year = 1972})
            carList.Add(New Cars With {.CarMake = "Porsche", .CarModel = "Maisto", .Year = 1976})
 
 
            Dim cc = _
                  From car As Cars In carList _
                  Where car.CarMake = "BMW" _
                  Select car
 
            Dim cc1 = _
                  From car In carList.Cast(Of Cars)() _
                  Where car.CarMake = "BMW" _
                  Select car
 
            Dim cc2 = _
                  From car In carList.OfType(Of Cars)() _
                  Where car.CarMake = "BMW" _
                  Select car
 
 
            For Each c As Cars In cc1
                  Console.WriteLine(c.CarMake & "-" & c.CarModel)
            Next c
 
            Console.ReadLine()
      End Sub
End Class
End Namespace
It’s a good decision on your part if you convert your nongeneric collections to generic ones to gain performance and strong type checking. However, meanwhile if you happen to use any nongeneric collections in your code and want to query them using LINQ, you can use the methods as discussed in this article. I hope this article was useful and I thank you for viewing it.
If you liked the article,  Subscribe to my RSS Feed.
 

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of DotNetCurry, DNC Magazine for Developers, SQLServerCurry and DevCurry. He has also authored a couple of books 51 Recipes using jQuery with ASP.NET Controls and The Absolutely Awesome jQuery CookBook.

Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.

Get in touch with him on Twitter @suprotimagarwal or at LinkedIn



Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!