In The Name Of ALLAH The Most Beneficent, Most Merciful.

Tuesday, 17 January 2017

LINQ-Specific Programming Constructs

From a high level, LINQ can be understood as a strongly typed query language, embedded directly into the grammar of C#. Using LINQ, you can build any number of expressions that have a look and feel similar to that of a database SQL query. However, a LINQ query can be applied to any number of data stores, including stores that have nothing to do with a literal relational database. When LINQ was first introduced to the .NET platform in version 3.5, the C# and VB languages were each expanded with a large number of new programming constructs used to support the LINQ technology set. Specifically, the C# language uses the following core LINQ-centric features:

  • Implicitly typed local variables
  • Object/collection initialization syntax
  • Lambda expressions
  • Extension methods
  • Anonymous types

These features have already been explored in detail within various chapters of the text. However, to get the ball rolling, let’s quickly review each feature in turn, just to make sure we are all in the proper mind-set.

LINQ To Objects

Regardless of the type of application you are creating using the .NET platform, your program will certainly need to access some form of data as it executes. To be sure, data can be found in numerous locations, including XML files, relational databases, in-memory collections, and primitive arrays. Historically speaking, based on the location of said data, programmers needed to make use of different and unrelated APIs. The Language Integrated Query (LINQ) technology set, introduced initially in .NET 3.5, provides a concise, symmetrical, and strongly typed manner to access a wide variety of data stores. In this chapter, you will begin your investigation of LINQ by focusing on LINQ to Objects.

Before you dive into LINQ to Objects proper, the first part of this chapter quickly reviews the key C# programming constructs that enable LINQ. As you work through this chapter, you will find that implicitly typed local variables, object initialization syntax, lambda expressions, extension methods, and anonymous types will be quite useful (if not occasionally mandatory).

 After this supporting infrastructure is reviewed, the remainder of the chapter will introduce you to the LINQ programming model and its role in the .NET platform. Here, you will come to learn the role of query operators and query expressions, which allow you to define statements that will interrogate a data source to yield the requested result set. Along the way, you will build numerous LINQ examples that interact with data contained within arrays as well as various collection types (both generic and nongeneric) and understand the assemblies,
, and types that represent the LINQ to Objects API.

The Semantics of Equality for Anonymous Types

While the implementation of the overridden ToString() and GetHashCode() methods is fairly straightforward, you might be wondering how the Equals() method has been implemented. For example, if you were to define two “anonymous cars” variables that specify the same name value pairs, would these two variables be considered equal? To see the results firsthand, update your Program type with the following new method:

static void EqualityTest()
{
// Make 2 anonymous classes with identical
name/value pairs.
var firstCar = new { Color = "Bright Pink", Make
= "Saab", CurrentSpeed = 55 };
var secondCar = new { Color = "Bright Pink", Make
= "Saab", CurrentSpeed = 55 };
// Are they considered equal when using Equals()?
if (firstCar.Equals(secondCar))
Console.WriteLine("Same anonymous object!");
else
Console.WriteLine("Not the same anonymous
object!");
// Are they considered equal when using ==?
if (firstCar == secondCar)
Console.WriteLine("Same anonymous object!");
else
Console.WriteLine("Not the same anonymous
object!");
// Are these objects the same underlying type?
if (firstCar.GetType().Name ==
secondCar.GetType().Name)
Console.WriteLine("We are both the same type!");
else
Console.WriteLine("We are different types!");
// Show all the details.
Console.WriteLine();
ReflectOverAnonymousType(firstCar);
ReflectOverAnonymousType(secondCar);

}
My car is a Bright Pink Saab.
You have a Black BMW going 90 MPH
ToString() == { Make = BMW, Color = Black, Speed = 90

}
Same anonymous object!
Not the same anonymous object!
We are both the same type!
obj is an instance of: <>f__AnonymousType0`3
Base class of <>f__AnonymousType0`3 is System.Object
obj.ToString() == { Color = Bright Pink, Make = Saab,
CurrentSpeed = 55 }
obj.GetHashCode() == -439083487
obj is an instance of: <>f__AnonymousType0`3
Base class of <>f__AnonymousType0`3 is System.Object
obj.ToString() == { Color = Bright Pink, Make = Saab,
CurrentSpeed = 55 }

obj.GetHashCode() == -439083487

When you run this test code, you will see that the first conditional test where you call Equals() returns true and, therefore, the message “Same anonymous object!” prints out to the screen. This is because the compiler-generated Equals() method uses value-based semantics when testing for equality (e.g., checking the value of each field of the objects being compared).

However, the second conditional test, which makes use of the C# equality operator (==), prints out “Not the same anonymous object!” This might seem at first glance to be a bit counterintuitive. This result is because anonymous types do not receive overloaded versions of the C# equality operators (== and !=). Given this, when you test for equality of anonymous types using the C# equality operators (rather than the Equals() method), the references, not the values maintained by the objects, are being tested for equality.

Last but not least, in the final conditional test (where you examine the underlying type name), you find that the anonymous types are instances of the same compiler generated class type (in this example, <>f AnonymousType0`3) because firstCar and secondCar have the same properties (Color, Make, and CurrentSpeed). 

This illustrates an important but subtle point: the compiler will generate a new class definition only when an anonymous type contains unique names of the anonymous type. Thus, if you declare identical anonymous types (again, meaning the same names) within the same assembly, the compiler generates only a single anonymous type definition.

Extension Methods

Understanding Extension Methods
.NET 3.5 introduced the concept of extension methods, which allow you to add new methods or properties to a class or structure, without modifying the original type in any direct manner. So, where might this be helpful? Consider the following possibilities.
First, say you have a given class that is in production. It becomes clear over time that this class should support a handful of new members. If you modify the current class definition directly, you risk the possibility of breaking backward compatibility with older code bases making use of it, as they might not have been compiled with the latest and greatest class definition. One way to ensure backward compatibility is to create a new derived class from the existing parent; however, now you have two classes to maintain. As we all know, code maintenance is the least glamorous part of a software engineer’s job description.
Now consider this situation. Let’s say you have a structure (or maybe a sealed class) and want to add new members so that it behaves polymorphically in your system. Since structures and sealed classes cannot be extended, your only choice is to add the members to the type, once again risking backward compatibility!
Using extension methods, you are able to modify types without subclassing and without modifying the type directly. To be sure, this technique is essentially a smoke-and-mirror show. The new functionality is offered to a type only if the extension methods have been referenced for use in your current project.
Defining Extension Methods
When you define extension methods, the first restriction is that they must be defined within a static class and, therefore, each extension method must be declared with the static keyword. The second point is that all extension methods are marked as such by using the this keyword as a modifier on the first (and only the first) parameter of the method in question. The “this qualified” parameter represents the item being extended.
To illustrate, create a new Console Application project named ExtensionMethods. Now, assume you are authoring a class named MyExtensions that defines two extension methods. The first method allows any object to use a new method named DisplayDefiningAssembly() that makes use of types in the System.Reflection namespace to display the

name of the assembly containing the type in question.
The second extension method, named ReverseDigits(), allows any int to obtain a new version of itself where the value is reversed digit by digit. For example, if an integer with the value 1234 called ReverseDigits(), the integer returned is set to the value 4321. Consider the following class implementation (be sure to import the System.Reflection namespace if you are following along):

static class MyExtensions
{
 // This method allows any object to display the assembly
 // it is defined in.
    public static void        DisplayDefiningAssembly(this object obj)
{
Console.WriteLine("{0} lives here: => {1}\n",
obj.GetType().Name,
Assembly.GetAssembly(obj.GetType()).GetName().Name);
}
// This method allows any integer to reverse its
digits.
// For example, 56 would return 65.
public static int ReverseDigits(this int i)
{
// Translate int into a string, and then
// get all the characters.
char[] digits = i.ToString().ToCharArray();
// Now reverse items in the array.
Array.Reverse(digits);
// Put back into string.
string newDigits = new string(digits);
// Finally, return the modified string back as an
int.
return int.Parse(newDigits);
}

}

Again, note how the first parameter of each extension method has been qualified with the this keyword, before defining the parameter type. It is always the case that the first parameter of an extension method represents the type being extended. Given that DisplayDefiningAssembly() has been prototyped to extend System.Object, every type now has this new member, as Object is the parent to all types in the .NET platform. However, ReverseDigits() has been prototyped to extend only integer types; therefore, if anything other than an integer attempts to invoke this method, you will receive a compile-time error.
End Of This Post
__Please Follow__

Collection And Generics

Any application you create with the .NET platform will need to contend with the issue of maintaining and manipulating a set of data points in memory. These data points can come from any variety of locations including a relational database, a local text file, an XML document, a web service call, or perhaps via userprovided input.

When the .NET platform was first released, programmers frequently used the classes of the System.Collections namespace to store and interact with bits of data used within an application. In .NET 2.0, the C# programming language was enhanced to support a feature termed generics; and with this change, a brand new namespace was introduced in the base class libraries: System.Collections.Generic.

This chapter will provide you with an overview of the various collection (generic and nongeneric) namespaces and types found within the .NET base class libraries. As you will see, generic containers are often favored over their nongeneric counterparts because they typically provide greater type safety and performance benefits. After you’ve learned how to create and manipulate the generic items found in the  , the  of this chapter will examine how to build your own generic methods and generic types. As you do this, you will learn about the role of constraints (and the corresponding C# wherekeyword), which allow you to build extremely type-safe classes.

Accessing a Namespace Programmatically

It is worth reiterating that a namespace is nothing more than a convenient way for us mere humans to logically understand and organize related types. Consider again the System namespace. From your perspective, you can assume that System.Console represents a class named Console that is contained within a namespace called System. However, in the eyes of the .NET runtime, this is not so. The runtime engine sees only a single class named System.Console.

In C#, the using keyword simplifies the process of referencing types defined in a particular namespace. Here is how it works. Let’s say you are interested in building a graphical desktop application using the WPF API. While learning the types each namespace contains takes study and experimentation, here are some possible candidates to reference in your program:

// Here are some possible namespaces used to build a WPF application.

using System; // General base class
library types.
using System.Windows.Shapes; // Graphical rendering types.
using System.Windows.Controls; // Windows Forms GUI widget types.
using System.Data; // General datacentric
types.
using System.Data.SqlClient; // MS SQL Server dataaccess types.

Once you have specified some number of namespaces (and set a reference to the assemblies that define them), you are free to create instances of the types they contain. For example, if you are interested in creating an instance of the Button class (defined in the System.Windows.Controls namespace), you can write the following:

// Explicitly list the namespaces used by this file.
using System;

using System.Windows.Controls;

class MyGUIBuilder
{
public void BuildUI()
 {
// Create a button control.
Button btnOK = new Button();
...
 }

}

Because your code file is importing the System.Windows.Controls namespace, the compiler is able to resolve the Button class as a member of this namespace. If you did not import the System.Windows.Controls namespace, you would be issued a compiler error. However, you are free to declare variables using a fully qualified name as well.

// Not listing System.Windows.Controls namespace!
using System;
class MyGUIBuilder
{
 public void BuildUI()
 {
  // Using fully qualified name.
  System.Windows.Controls.Button btnOK =
  new System.Windows.Controls.Button();
  ...
 }

}

While defining a type using the fully qualified name provides greater readability, I think you’d agree that the C# using keyword reduces keystrokes. In this text, I will avoid the use of fully qualified names (unless there is a definite ambiguity to be resolved) and opt for the simplified approach of the C# using keyword.

However, always remember that the using keyword is simply a shorthand notation for specifying a type’s fully qualified name, and either approach results in the same underlying CIL (given that CIL code always uses fully qualified names) and has no effect on performance or the size of the assembly.
 End Of This Post
__Please Follow__

The Assembly/Namespace/Type Distinction

Each of us understands the importance of code libraries. The point of framework libraries is to give developers a well defined set of existing code to leverage in their applications. However, the C# language does not come with a languagespecific code library. Rather, C# developers leverage the language- neutral .NET libraries. To keep all the types within the base class libraries well organized, the .NET platform makes extensive use of the namespace concept.

A namespace is a grouping of semantically related types contained in an assembly or possibly spread across multiple related assemblies. For example, the System.IO namespace contains file I/O-related types, the System.Data namespace defines basic database types, and so on. It is important to point out that a single assembly (such as mscorlib.dll) can contain any number of namespaces, each of which can contain any number of types.

To Clarify the following figure 1.3 shows the Visual Studio Object Browser utility (which can be found under the View menu). This tool allows you to examine the assemblies referenced by your current project, the namespaces within a particular assembly, the types within a given namespace, and the members of a specific type. Note that the mscorlib.dll assembly contains many different namespaces (such as System.IO), each with its own semantically related types (e.g., BinaryReader).


Figure Shows. A single assembly can have any number of namespaces, and namespaces can have any number of types.
             End Of This Post
       __Please Follow__

Popular Posts

 
Real Time Web Analytics