Infosys Microsoft Alliance and Solutions blog

« Loading Multiple Versions of same Assembly | Main | Where are ASP.NET 2.0 Website Project Properties Stored? »

LINQ and its linkage to new features in .NET Framework 3.5 - Part II,,,

In my previous blog “LINQ and its linkage to new features in .NET Framework 3.5 – Part I”, we have seen how a query can be expressed with clarity with object oriented programming notation and couple of code snippets that showed how a class can be extended through “extension” methods – a concept that is introduced in .NET Framework 3.5. It is really important to know that when the query gets executed at runtime. The following code snippet shows the usage of query expression.

IEnumerable<string> name = Names.OrderBy(s => s.Length)
                        .Where(s => s.Length >= 15)
                        .Select(s => s);

The query execution does not happen in this line of code, though it uses the assignment operation. Only when, looping is happening through the foreach statement of IEnumerable[] items, the query gets executed.

See the following code.

 

IEnumerable<string> name = Names.OrderBy(s => s.Length)
                        .Where(s => s.Length >= 15)
                        .Select(s => s);
            Names.SetValue("All's Well That Ends Well", 5);
           
            Console.WriteLine("Shakespeare's play - All's Well That Ends Well - is added into Names,,,");
            Console.WriteLine("=======================");
            foreach (string str in name)
            {
                Console.WriteLine("{0}", str);
            }

            Console.WriteLine("=======================");

After assigning the query expression to the type “IEnumerable<string>”, I changed the first element of “Names” to be a Shakespeare’s work – “All’s Well That Ends Well”. Then I do the looping for displaying the result that outputs only the Shakespeare’s works. The Console output now shows this play as well on the screen.

LINQ Part 02 Image

 

This dynamism is very essential when the application deals with highly flux data, on which query is executed.

However, if the changes to the source type happen with in looping logic, we can’t expect the query execution to reflect on those changes. In the following code snippet, change to “Names” is done from within the foreach construct. The output will not reflect this change. But, the updated change will be reflected in the console, in the second looping.

IEnumerable<string> name = Names.OrderBy(s => s.Length)
                        .Where(s => s.Length >= 15)
                        .Select(s => s);
            Names.SetValue("All's Well That Ends Well", 5);
           
Console.WriteLine("Shakespeare's play - All's Well That Ends Well - is added into Names,,,");


            foreach (string str in name)
            {
                if (string.Compare(str, "All's Well That Ends Well") == 0)
                {
                    Names.SetValue("Much Ado About Nothing", 8);
                    Console.WriteLine("Shakespeare's play - Much Ado    About Nothing - is added into Names,,,");
                }


                Console.WriteLine("{0}", str);


            }


            Console.WriteLine("======================");
            Console.WriteLine("During Second Run,,,");
            Console.WriteLine("======================");
            foreach (string str in name)
            {
                Console.WriteLine("{0}", str);
            }


            Console.WriteLine("=======================");


Console output

LINQ Part 02 Image 02

Now, another twist to this story is all is not really well if there are two static classes that implement the extension method with the same name. Let us assume that we need to build another static class “HenrikIbsenWords” that will have the extension method with the same name (“Select”) as that of “ShakespeareWorks”. That extension method is designed to select only Henrik Ibsen’s plays.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Linq.Expressions;
namespace System.HenrikIbsenQuery
{
    public static class HenrikIbsenWorks
    {
        public static IEnumerable<T> Select<T>(this IEnumerable<T> source, Func<T, string> selector)
        {
            string[] dramasList = {
                                       "The Pretenders",
                                       "Peer Gynt",
                                       "Emperor and Galilean",
                                       "A Doll's House",
                                       "An Enemy of the People",
                                       "The Wild Duck",
                                       "Hedda Gabler",
                                       "The Master Builder"                             
                                      
                                   };
            foreach (T item in source)
            {
                foreach (string str in dramasList)
                {
                    if (string.Compare(item.ToString().ToLower(), str.ToLower()) == 0)
                        yield return item;
                }
            }
        }
    }

}

And if we need to use them interchangeably in the code, by importing namespaces of both those classes (as given in the following code snippet), we will get the following error message during build time.

The call is ambiguous between the following methods or properties:

'System.HenrikIbsenQuery.HenrikIbsenWorks.Select<string>(System.Collections.Generic.IEnumerable<string>, System.Linq.Func<string,string>)'

and

'System.ShakespeareQuery.ShakespeareWorks.Select<string>(System.Collections.Generic.IEnumerable<string>, System.Linq.Func<string,string>)'        

Code Snippet

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.ShakespeareQuery;
using System.HenrikIbsenQuery;
using System.MyStringExtensionNS;
namespace MyConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] Names = {   "Waiting for Godot",
                                 "Death of a Salesman",
                                 "Rosencrantz and Guildenstern Are Dead",
                                 "The Devil's Disciple",
                                 "Mrs. Warren's Profession",
                                 "Arms and the Man",
                                 "Candida",
                                 "You Never Can Tell",
                                 "Caesar and Cleopatra",
                                 "Man and Superman",
                                 "Major Barbara",
                                 "The Doctor's Dilemma",
                                 "Pygmalion",
                                 "My Fair Lady",
                                 "The Pretenders",
                                 "Peer Gynt",
                                 "Emperor and Galilean",
                                 "A Doll's House",
                                 "An Enemy of the People",
                                 "The Wild Duck",
                                 "Hedda Gabler",
                                 "The Master Builder",
                                 "Hamlet",
                                 "Macbeth",
                                 "Othello",
                                 "Venus and Adonis",
                                 "A Midsummer Night's Dream",
                                 "As You Like It",
                                 "Henry VI Part I",
                                 "Henry V",
                                 "Henry IV Part I",
                                 "Henry VIII",
                                 "Richard II",
                                 "Richard III"                                 
                             };
           
           
            IEnumerable<string> name = Names.OrderBy(s => s.Length)
                        .Where(s => s.Length > 0)
                        .Select(s => s);
                        
                       
            foreach (string str in name)
            {
                Console.WriteLine("{0}", str);
            }
            Console.WriteLine("=======================");
            Console.Read();
        }
    }
}
If more than one namespace that are imported into a code, contain extension methods with the same name, it will create the ambiguity problem as we have just seen. But those namespace may contain some other methods that may need to be accessed by our code. In such circumstances, we can mitigate this ambiguity issue through the usage of namespace alias.
In the following code snippet, I have ensured that the extension method of “HenrikIbsenWork” class that is in “System.HenrikIbsenQuery” namespace is being applied to the “Names” type.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Shakespeare = System.ShakespeareQuery;
using System.HenrikIbsenQuery;
using System.MyStringExtensionNS;
namespace MyConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] Names = {   "Waiting for Godot",
                                 "Death of a Salesman",
                                 "Rosencrantz and Guildenstern Are Dead",
                                 "The Devil's Disciple",
                                 "Mrs. Warren's Profession",
                                 "Arms and the Man",
                                 "Candida",
                                 "You Never Can Tell",
                                 "Caesar and Cleopatra",
                                 "Man and Superman",
                                 "Major Barbara",
                                 "The Doctor's Dilemma",
                                 "Pygmalion",
                                 "My Fair Lady",
                                 "The Pretenders",
                                 "Peer Gynt",
                                 "Emperor and Galilean",
                                 "A Doll's House",
                                 "An Enemy of the People",
                                 "The Wild Duck",
                                 "Hedda Gabler",
                                 "The Master Builder",
                                 "Hamlet",
                                 "Macbeth",
                                 "Othello",
                                 "Venus and Adonis",
                                 "A Midsummer Night's Dream",
                                 "As You Like It",
                                 "Henry VI Part I",
                                 "Henry V",
                                 "Henry IV Part I",
                                 "Henry VIII",
                                 "Richard II",
                                 "Richard III"                                
                             };
           
           
            IEnumerable<string> name = Names.OrderBy( s => s.Length )
                                        .Where( s => s.Length > 0 )
                                        .Select( s => s );
                                     
            foreach (string str in name)
                Console.WriteLine("{0}", str);
            Console.WriteLine("=======================");  
            Console.Read();
        }
    }
}

Console ouput

LINQ Part 02 Image

We will see the details about LINQ over database and XML in future blogs.

Comments

Ganesan, what's the purpose of .Select(s => s) ?

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter