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 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 interface. However nongeneric
collections like the ArrayList do not implement the IEnumerable 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
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
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. Once we get an
IEnumerable, we can then query the collection using LINQ.
C#
var cc1 = from car in carList.Cast()
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()
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()
where car.CarMake == "BMW"
select car;
var cc2 = from car in carList.OfType()
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.
No comments:
Post a Comment