Vous est-il déjà arrivé de vouloir utiliser Linq sur une liste ou une collection qui ne supporte pas Linq?

Je peux prendre l’exemple de l’ArrayList qui ne le permet pas.

Il existe malgré tout un moyen de contourner ce problème via deux méthodes d’extension : OfType et Cast.

Ces deux méthodes sont disponibles depuis la version 3.5 du Framework .Net.

Elles renvoient toutes les deux un IEnumerable qui supporte Linq mais ne fonctionnent pas de la même manière.

Là où OfType filtre par type d’objet, Cast quand à lui transforme les objets suivant le type fourni.

OfType

Prenons notre ArrayList tel que défini ci-dessous :

ArrayList arrayList = new ArrayList();

arrayList.Add(
    new WebCustomer
    {
        FirstName = "Bob",
        LastName = "Morane",
        Website = @"http://nicolas-cousin.com/"
    });

arrayList.Add(
    new WebCustomer
    {
        FirstName = "Morgan",
        LastName = "Freeman",
        Website = @"http://nicolas-cousin.com/"
    });

arrayList.Add(
    new LiveCustomer
    {
        FirstName = "Liv",
        LastName = "Boree",
        ShopName = @"Mon Magasin Live"
    });

arrayList.Add(
    new BlogArticle
    {
        Title = "OfType et Cast"
    });

Et utilisons OfType pour afficher les informations suivant leur type :

arrayList.OfType<WebCustomer>().ToList().ForEach(c =>
{
    Console.WriteLine("{0} {1} {2}", c.FirstName, c.LastName, c.Website);
});

arrayList.OfType<LiveCustomer>().ToList().ForEach(c =>
{
    Console.WriteLine("{0} {1} {2}", c.FirstName, c.LastName, c.ShopName);
});

arrayList.OfType<Customer>().ToList().ForEach(c =>
{
    Console.WriteLine("{0} {1}", c.FirstName, c.LastName);
});

arrayList.OfType<BlogArticle>().ToList().ForEach(c =>
{
    Console.WriteLine("{0}", c.Title);
});

Voici le résultat :

OfType

Explication :

OfType à filtré le résultat par type d’objet : WebCustomer et LiveCustomer qui héritent de Customer tous les deux ce qui explique la troisième requête.

Cast

Si nous essayons de faire l’une de ces requêtes en utilisant Cast à la place nous aurons une erreur car Cast cherche a tout transformer dans le type demandé.

Modifions notre liste pour retirer le BlogArticle :

ArrayList arrayList = new ArrayList();

arrayList.Add(
    new WebCustomer
    {
        FirstName = "Bob",
        LastName = "Morane",
        Website = @"http://nicolas-cousin.com/"
    });

arrayList.Add(
    new WebCustomer
    {
        FirstName = "Morgan",
        LastName = "Freeman",
        Website = @"http://nicolas-cousin.com/"
    });

arrayList.Add(
    new LiveCustomer
    {
        FirstName = "Liv",
        LastName = "Boree",
        ShopName = @"Mon Magasin Live"
    });

Vérifions la requête suivante :

arrayList.Cast<WebCustomer>().ToList().ForEach(c =>
{
    Console.WriteLine("{0} {1} {2}", c.FirstName, c.LastName, c.Website);
});

Résultat :

Une exception du type  System.InvalidCastException est levée.

Vérifions ensuite la requête :

arrayList.Cast<LiveCustomer>().ToList().ForEach(c =>
{
    Console.WriteLine("{0} {1} {2}", c.FirstName, c.LastName, c.ShopName);
});

Résultat :

Une exception du type  System.InvalidCastException est levée.

Vérifions pour finir la requête :

arrayList.Cast<Customer>().ToList().ForEach(c =>
{
    Console.WriteLine("{0} {1}", c.FirstName, c.LastName);
});

Résultat :

OfType

Conclusion

Dans l’utilisation des deux méthodes, il faut distinguer leur mode de fonctionnement.

OfType va donc filtrer pour ne sortir que les éléments correspondant au type demandé.

Cast va essayer de transformer tous les objets dans le type demandé et provoquerai une erreur s’il ne peut pas le faire pour un élément.