Professional Documents
Culture Documents
C# Notes
Appeared in 2001
Designed by Microsoft
Developer Microsoft
Typing
static, dynamic, strong, safe, nominative
discipline
Major
implementatio .NET Framework, Mono, DotGNU
ns
Usual file
.cs
extensions
C#
The name "C sharp" was inspired by musical notation where a sharp indicates that the written note
should be made a semitone higher in pitch. This is similar to the language name of C++, where "++"
indicates that a variable should be incremented by 1.
Due to technical limitations of display (standard fonts, browsers, etc.) and the fact that the sharp symbol
♯ Music Sharp sign is not present on the standard keyboard, the number sign # Number sign was
chosen to represent the sharp symbol in the written name of the programming language. This convention
is reflected in the ECMA-334 C# Language Specification. However, when it is practical to do so (for
example, in advertising or in box art), Microsoft uses the intended musical symbol.
The "sharp" suffix has been used by a number of other .NET languages that are variants of existing
languages, including J# (a .NET language also designed by Microsoft which is derived from Java 1.1),
A# (from Ada), and the functional F#. The original implementation of Eiffel for .NET was called
Eiffel#, a name since retired since the full Eiffel language is now supported. The suffix has also been
used for libraries, such as Gtk# (a .NET wrapper for GTK+ and other GNOME libraries), Cocoa# (a
wrapper for Cocoa) and Qt# (a .NET language binding for the Qt toolkit).
History
During the development of the .NET Framework, the class libraries were originally written using a
managed code compiler system called Simple Managed C (SMC). In January 1999, Anders Hejlsberg
formed a team to build a new language at the time called Cool, which stood for "C-like Object Oriented
Language". Microsoft had considered keeping the name "Cool" as the final name of the language, but
chose not to do so for trademark reasons. By the time the .NET project was publicly announced at the
July 2000 Professional Developers Conference, the language had been renamed C#, and the class
libraries and ASP.NET runtime had been ported to C#.
C#'s principal designer and lead architect at Microsoft is Anders Hejlsberg, who was previously
involved with the design of Turbo Pascal, Embarcadero Delphi (formerly CodeGear Delphi and Borland
Delphi), and Visual J++. In interviews and technical papers he has stated that flaws in most major
programming languages (e.g. C++, Java, Delphi, and Smalltalk) drove the fundamentals of the Common
Language Runtime (CLR), which, in turn, drove the design of the C# language itself.
James Gosling, who created the Java programming language in 1994, and Bill Joy, a co-founder of Sun
Microsystems, the originator of Java, called C# an "imitation" of Java; Gosling further claimed that "[C#
is] sort of Java with reliability, productivity and security deleted." Klaus Kreft and Angelika Langer
(authors of a C++ streams book) stated in a blog post that "Java and C# are almost identical
programming languages. Boring repetition that lacks innovation," "Hardly anybody will claim that Java
or C# are revolutionary programming languages that changed the way we write programs," and "C#
borrowed a lot from Java - and vice versa. Now that C# supports boxing and unboxing, we'll have a very
similar feature in Java." Anders Hejlsberg has argued that C# is "not a Java clone" and is "much closer
to C++" in its design.
Since the release of C# 2.0 in November of 2005, the C# and Java languages have evolved on
increasingly divergent trajectories, becoming somewhat less similar. One of the first major departures
came with the addition of generics to both languages, with vastly different implementations. C# makes
use of reification to provide "first-class" generic objects that can be used like any other class, with code
generation performed at class-load time. By contrast, Java's generics are essentially a language syntax
feature, and they do not affect the generated byte code because the compiler performs type erasure on
the generic type information after it has verified its correctness.
Aishwarya Lakshmi 4
C# Notes
Summary of c# versions
The .NET Framework is a new and revolutionary platform created by Microsoft for developing
C# 2.0 C# 3.0 C# 4.0 C# 5.0
(planned)
Method group Implicitly typed Dynamic Asynchronous
conversions local variables binding methods
(delegates) Object and
collection
initializers
Private setters Auto- Named and
Featur (properties) Implemented optional
es properties arguments
Nullable types Anonymous
added types
Iterators Extension Compiler as a
methods service
Anonymous methods Query Generic co-
expressions and
Partial types Lambda contravariance
expressions
Generics Expression trees
applications.
• It is a platform for application developers.
• It is a Framework that supports Multiple Language and Cross language integration.
• IT has IDE (Integrated Development Environment).
• Framework is a set of utilities or can say building blocks of your application system.
• .NET Framework provides GUI in a GUI manner.
• .NET is a platform independent but with help of Mono Compilation System (MCS). MCS is
a middle level interface.
• .NET Framework provides interoperability between languages i.e. Common Type System
(CTS) .
• .NET Framework also includes the .NET Common Language Runtime (CLR), which is
responsible for maintaining the execution of all applications developed using the .NET
library.
• The .NET Framework consists primarily of a gigantic library of code.
Definition: A programming infrastructure created by Microsoft for building, deploying, and running
applications and services that use .NET technologies, such as desktop applications and Web services.
Aishwarya Lakshmi 7
C# Notes
You can use a utility of a language in another language (It uses Class Language Integration).
.NET Framework includes no restriction on the type of applications that are possible. The .NET
Framework allows the creation of Windows applications, Web applications, Web services, and lot more.
The .NET Framework has been designed so that it can be used from any language, including C#, C++,
Visual Basic, JScript, and even older languages such as COBOL.
Web Application
All websites are example of web application. They use a web server.
Peer to Peer
Communication through computers through some system.
Web Services
It doesn't use web-based server. Internet payment systems are example of web services.
DLL Hell
"DLL Hell" refers to the set of problems caused when multiple applications attempt to share a common
component like a dynamic link library (DLL) or a Component Object Model (COM) class.
The reason for this issue was that the version information about the different components of an
application was not recorded by the system. (Windows Registry cannot support the multiple versions of
same COM component this is called the dll hell problem.)
.Net Framework provides operating systems with a Global Assembly Cache (GAC). This Cache is a
repository for all the .Net components that are shared globally on a particular machine. When a .Net
component is installed onto the machine, the Global Assembly Cache looks at its version, its public key,
Aishwarya Lakshmi 8
C# Notes
and its language information and creates a strong name for the component. The component is then
registered in the repository and indexed by its strong name, so there is no confusion between different
versions of the same component, or DLL.
Similarly, when it comes to computer programs, we need some mechanism or medium for
communication. Primarily, processes can use the available memory to communicate with each other. But
then, the memory is completely managed by the operating system. A process will be allotted some part
of the available memory for execution. Then each process will have its own unique user space. In no
way will the memory allotted for one process overlap with the memory allotted for another process.
Imagine what would happen otherwise!
So, now the question - how do different processes with unique address space communicate with each
other? The operating system's kernel, which has access to all the memory available, will act as the
communication channel. Similar to our earlier example, where the glass with hot water is one process
address space, the glass with cold water is another, and the glass with the larger capacity is the kernel
address space, so that we pour both hot water and cold water into the glass with larger capacity.
Aishwarya Lakshmi 9
C# Notes
Code Manager
Code manager invokes class loader for execution.
It is a subset of CTS. All instruction is in CLS i.e. instruction of CTS is written in CLS. CTS checks for
its type.
1. Reference Type.
➢ Class.
○ Inheritance.
○ Interfaces.
1) Managed Code
2) Unmanaged Code
Managed Code
The resource, which is with in your application domain is, managed code. The resources that are within
domain are faster. The code, which is developed in .NET framework, is known as managed code. This
code is directly executed by CLR with help of managed code execution. Any language that is written
in .NET Framework is managed code. Managed code uses CLR which in turns looks after your
applications by managing memory, handling security, allowing cross - language debugging, and so on.
Aishwarya Lakshmi 12
C# Notes
Unmanaged Code
The code, which is developed outside .NET, Framework is known as unmanaged code.
Applications that do not run under the control of the CLR are said to be unmanaged, and certain
languages such as C++ can be used to write such applications, which, for example, access low - level
functions of the operating system. Background compatibility with code of VB, ASP and COM are
examples of unmanaged code.
Unmanaged code can be unmanaged source code and unmanaged compile code.
Native Code
The code to be executed must be converted into a language that the target operating system understands, known as
native code. This conversion is called compiling code, an act that is performed by a compiler.
Under the .NET Framework, however, this is a two - stage process. With help of MSIL and JIT.
Instead, you compile your code into Microsoft Intermediate Language (MSIL) code. The MSIL code is
not specific to any operating system or to any language.
JIT (Just-in-Time)
Just - in - Time (JIT) compiler, which compiles MSIL into native code that is specific to the OS and
machine architecture being targeted. Only at this point can the OS execute the application. The just - in -
time part of the name reflects the fact that MSIL code is only compiled as, and when, it is needed.
In the past, it was often necessary to compile your code into several applications, each of which targeted
a specific operating system and CPU architecture. Often, this was a form of optimization.
Aishwarya Lakshmi 15
C# Notes
This is now unnecessary, because JIT compilers (as their name suggests) use MSIL code, which is
independent of the machine, operating system, and CPU. Several JIT compilers exist, each targeting a
different architecture, and the appropriate one will be used to create the native code required.
The beauty of all this is that it requires a lot less work on your part - in fact, you can forget about system
- dependent details and concentrate on the more interesting functionality of your code.
Econo JIT
It will convert the called executable code only. But it will convert code every time when a code is called
again.
Normal JIT
It will only convert the called code and will store in cache so that it will not require converting code
again. Normal JIT is fast.
Assemblies
When you compile an application, the MSIL code created is stored in an assembly. Assemblies include
both executable application files that you can run directly from Windows without the need for any other
programs (these have a .exe file extension), and libraries (which have a .dll extension) for use by other
applications.
In addition to containing MSIL, assemblies also include meta information (that is, information about the
information contained in the assembly, also known as metadata) and optional resources (additional data
used by the MSIL, such as sound files and pictures).
The meta information enables assemblies to be fully self - descriptive. You need no other information to
use an assembly, meaning you avoid situations such as failing to add required data to the system registry
and so on, which was often a problem when developing with other platforms.
This means that deploying applications is often as simple as copying the files into a directory on a
remote computer. Because no additional information is required on the target systems, you can just run
an executable file from this directory and (assuming the .NET CLR is installed) you're good to go.
Of course, you won't necessarily want to include everything required to run an application in one place.
You might write some code that performs tasks required by multiple applications. In situations like that,
it is often useful to place the reusable code in a place accessible to all applications. In the .NET
Framework, this is the Global Assembly Cache (GAC). Placing code in the GAC is simple - you just
place the assembly containing the code in the directory containing this cache.
Aishwarya Lakshmi 16
C# Notes
ARRAYS
Arrays works as collections of items, for instance strings. You can use them to gather items in a single
group, and perform various operations on them, e.g. sorting. Besides that, several methods within the
framework work on arrays, to make it possible to accept a range of items instead of just one. This fact
alone makes it important to know a bit about arrays.
Arrays are declared much like variables, with a set of [] brackets after the datatype, like this:
string[] names;
You need to instantiate the array to use it, which is done like this:
The number (2) is the size of the array, that is, the amount of items we can put in it. Putting items into
the array is pretty simple as well:
But why 0? As it is with so many things in the world of programming, the counting starts from 0 instead
of 1. So the first item is indexed as 0, the next as 1 and so on. You should remember this when filling
the array with items, because overfilling it will cause an exception. When you look at the initializer,
setting the array to a size of 2, it might seem natural to put item number 0, 1 and 2 into it, but this is
one item too much. If you do it, an exception will be thrown. We will discuss exceptions in a later
chapter.
Earlier, we learned about loops, and obviously these go great with arrays. The most common way of
getting data out of an array, is to loop through it and perform some sort of operation with each value.
Let's use the array from before, to make a real example:
using System;
using System.Collections;
namespace ConsoleApplication1
class Program
{
Aishwarya Lakshmi 17
C# Notes
foreach(string s in names)
Console.WriteLine(s);
Console.ReadLine();
We use the foreach loop, because it's the easiest, but of course we could have used one of the other
types of loop instead. The for loop is good with arrays as well, for instance if you need to count each
item, like this:
It's actually very simple. We use the Length property of the array to decide how many times the loop
should iterate, and then we use the counter (i) to output where we are in the process, as well as get the
item from the array. Just like we used a number, a so called indexer, to put items into the array, we can
use it to get a specific item out again.
I told you earlier that we could use an array to sort a range of values, and it's actually very easy. The
Array class contains a bunch of smart methods for working with arrays. This example will use numbers
instead of strings, just to try something else, but it could just as easily have been strings. I wish to show
you another way of populating an array, which is much easier if you have a small, predefined set of
items that you wish to put into your array. Take a look:
With one line, we have created an array with a size of 5, and filled it with 5 integers. By filling the array
like this, you get an extra advantage, since the compiler will check and make sure that you don't put too
many items into the array. Try adding a number more - you will see the compiler complain about it.
int[] numbers = { 4, 3, 8, 0, 5 };
This is short, and you don't have to specify a size. The first approach may be easier to read later on
though.
using System;
using System.Collections;
namespace ConsoleApplication1
class Program
int[] numbers = { 4, 3, 8,
0, 5 };
Array.Sort(numbers);
foreach(int i in numbers)
Console.WriteLine(i);
Console.ReadLine();
The only real new thing here is the Array.Sort command. It can take various parameters, for various
kinds of sorting, but in this case, it simply takes our array. As you can see from the result, our array has
Aishwarya Lakshmi 19
C# Notes
been sorted. The Array class has other methods as well, for instance the Reverse() method. You can
look it up in the documentation to see all the features of the Array class.
The arrays we have used so far have only had one dimension. However, C# arrays can be
multidimensional, sometimes referred to as arrays in arrays. Multidimensional arrays come in two
flavors with C#: Rectangular arrays and jagged arrays. The difference is that with rectangular arrays, all
the dimensions have to be the same size, hence the name rectangular. A jagged array can have
dimensions of various sizes. Multidimensional arrays are a heavy subject, and a bit out of the scope of
this tutorial.
Other Versions
Covariance and contravariance provide a degree of flexibility when matching method signatures with
delegate types. Covariance permits a method to have a more derived return type than what is defined in
the delegate. Contravariance permits a method with parameter types that are less derived than in the
delegate type.
Example 1 (Covariance)
This example demonstrates how delegates can be used with methods that have return types that are
derived from the return type in the delegate signature. The data type returned by SecondHandler is of
type Dogs, which derives from the Mammals type that is defined in the delegate.
VB
Aishwarya Lakshmi 20
C# Notes
C#
C++
F#
JScript
Copy
class Mammals
class Program
return null;
return null;
Example 2 (Contravariance)
This example demonstrates how delegates can be used with methods that have parameters of a type
that are base types of the delegate signature parameter type. With contravariance, you can now use one
event handler in places where, previously, you would have had to use separate handlers. For example,
you can now create an event handler that accepts an EventArgs input parameter and use it with the
Button.MouseClick event that sends a MouseEventArgs type as a parameter, and also with
TextBox.KeyDown event that sends a KeyEventArgs parameter.
VB
C#
C++
F#
JScript
Aishwarya Lakshmi 22
C# Notes
Copy
System.DateTime lastActivity;
public Form1()
InitializeComponent();
lastActivity = System.DateTime.Now;
Covariance is basically using a method which returns something derived from the expected
type.
An exemple ? It’s safe to have a method returning a cat when you expect it to return an animal.
In C sharp it’s
// It's safe to say that something returns a Animal when in fact this
thing returns a Cat
class Covariance
{
Aishwarya Lakshmi 24
C# Notes
void test()
Func<Animal> a = Method; // OK
Cat Method()
So Funcs a, b, and c are returning animals which in fact are cats, which is true.
// It's safe to say that something can take a Cat if in fact this thing
can take any Animal
class Contravariance
{
Aishwarya Lakshmi 25
C# Notes
Action<Cat> a = Method; // OK
So Action a take Cats, but in fact can take any Animals, so it’s safe
Ienumerators
Description
We know how to use foreach for built-in types of C#.But how do we Use for objects of our class.
For
Aishwarya Lakshmi 26
C# Notes
class Employee
{
}
Step#1:
To foreach construct for user-defined classes the first thing we have to do is Imlplement the
interface IEnumerable. Then Ienumerable interface has a method called GetEnumerator() which
returns an object of IEnumerator.
Step#2:
Next we have to implement IEnumerator interface.The IEnumerator has 3 methods namely
Reset(),Current(),MoveNext().After we code for the 3 methods we are able to use foreach() for our
UDC(User Defined Classes).
Step#3:
How does foreach works when we use foreach() construct it first Calls MoveNext() if it returns true
then the loop is continued to the value from the Current() method call.Reset() is used to set the
Enumerator to begining position.
Let's run through a coding sample which will make things clear:
The source code has 2 classes namely Employee,Employees. Employee class hold information
about each Employee. The Employees class hold array of Employee objects.
Source Code Explanation:
1. Create Employees class object
EmpList.AddEmployee(e1);
EmpList.AddEmployee(e2);
When this statement is executed it will call the GetEnumerator() method of the Employees
class to get the IEnumerator object.Then it calls the MoveNext() method since it returns
true it calls the Current() method and return the Employee object.which is printed.this same
sequence is repeated for 2nd Employee.During the third time call MoveNext() returns false
and it exits the foreach construct.
Aishwarya Lakshmi 27
C# Notes
5. To clearly get the underhood of Enumerator() see the code below which does the above
sequence:
possible to do this with the List class) that illustrates how you would go about implementing these to
iterate over a collection of string objects:
using System;
using System.Collections.Generic;
using System.Collections;
namespace Demo
_values = values;
IEnumerator IEnumerable.GetEnumerator()
return GetEnumerator();
}
Aishwarya Lakshmi 30
C# Notes
Reset();
object IEnumerator.Current
_currentIndex++;
_currentIndex = -1;
I’m sure there’s a better way to do this, but it should help you get started. Note that you have to
implement both classes and that the most work is done in the class that implements IEnumerator. Also
note that you can use generics (in this case force it to iterate only over string objects).
You would invoke this functionality this way:
collection.Add("abc");
collection.Add("def");
collection.Add("ghi");
Console.Out.WriteLine(x);
Anonymous types
Aishwarya Lakshmi 32
C# Notes
With the introduction of .NET 3.5 C# includes the “var” keyword to support anonymous types. One
important motivation for this was to make code written with LINQ (Language-Integrated Query) easier
to read. So what is an anonymous type? Anonymous types simply mean that you don’t specify the type —
but let the compiler do it instead.
To understand how LINQ works, and to realize that its more than just syntactic sugar added to C# we
first need to review a couple of basic concepts that when combined lead to LINQ.
Simple definitions, simplified
In typical C# you will always carefully spell out your definitions:
string MyString = “Hello World”;
From the right side of the declaration it is obvious that only one type (string) will ever match this
definition. So instead of us doing the work, why not let the compiler figure this out?
var MyString = “Hello World”;
The above definition will also create a string variable named “MyString”. It is important to note that C#
is still strongly typed — unlike scripted languages such as Visual Basic (or PHP) once you have
assigned the variable type it sticks. The following will not work:
var MyString2 = “Hello World”;
MyString2 = 123; // Nice try, but no banana
The compiler will throw an implicit conversion error as 123 cannot be assigned to a string.
The above was an impressive (if somewhat pointless) example of what an anonymous type is. For
simple types such as strings, integers etc anonymous types offer little benefits. It is even possible to
argue that it reduces your code readability.
Using anonymous types for creating arrays
We are not limited to simple types – the following example show how we can create an anonymous
array of integers:
int[] myIntArray = new int[] { 1 , 2 , 3 , 4 , 5 , 6 };
var myIntArrayVar = new [] { 1 , 2 , 3 , 4 , 5 , 6 };
The above two examples are equivalent. You still need to specify that you want to create an array using
new. You are however limited by how flexible the compiler is. A mixed array is a little too much and we
need to force it down to an object array:
var myMixedArray = new [] { 1, “two” , 3 , “four” , 5 }; // this does NOT work
object[] myMixedArray = new object[] { 1, “two” , 3 , “four” , 5 }; // this is OK
Saving time and code with anonymous types
One very powerful feature of anonymous types it that they can save you a lot of work. Instead of having
to type out everything explicitly, you can have the compiler infer the definition of a complete class:
view sourceprint?
01.using System;
02.class MainClass
03.{
Aishwarya Lakshmi 33
C# Notes
05. {
08. }
09.}
The compiler creates an anonymous definition of a class and assigns to it Name and Age as public
fields. We can combine anonymous classes and anonymous arrays to create an Employee data structure.
Note that we use a “Var” in the ForEach loop. Because we are combining anonymous types it is
impossible to determine the correct type to loop over each element in the array. Thankfully we can ask
the compiler to fill in the correct iterator type for us:
view sourceprint?
01.using System;
02.class MainClass
03.{
05. {
11. }
12.}
As Employees is an array we can use an iterator to step through it as shown above, but we can just as
easily use a for loop:
view sourceprint?
01.using System;
02.class MainClass
03.{
Aishwarya Lakshmi 34
C# Notes
05. {
11. }
12.}
01.using System;
02.using System.Linq;
04. {
06. {
14. }
15. }
From the above you can see that the compiler needs to infers,create and apply several anonymous types
to create a working code sample. We thankfully can use “var” to specify our SeniorStaff sub-set. Behind
the scenes the compiler has created an anonymous IEnumberable for SeniorStaff that contains our
Employee records with anonymous staff members. And for the Where method it applied an anonymous
delegate to create the correct filter.
And this leads us to the first real “LINQ” statement.
var SeniorStaff = from S in Employees where S.Age > 35 select S;
When you take away the syntactic sugar the C# compiler will build from this the same (or very similar)
“Employees.Where(s => s.Age > 35)” statement. Using the same anonymous methods, variables and
functions as we used earlier.
This took a lot of getting to. It is however important to understand that LINQ is implemented in C#
through basic, strongly typed variables and methods.
To keep the complexity of our C# code down the “var” keyword was added allowing the programmer to
focus on coding the logic of the program instead of having to write long hand type definitions for each
variable.
Q. Is var typesafe?
There’s no concern about type-safety, as the variable created is not dynamic. It’s just compiler magic
and any type unsafe calls you make will get caught.
Q. Is there a performance penalty for using “var” ?
The var keyword only tells the compiler to infer the type from the assignment, there’s no runtime
difference, so no, there’s no penalty performance wise.
Q. On using anonymous definitions in large projects
Aishwarya Lakshmi 36
C# Notes
Anonymous types cannot be shared across assembly boundaries. The compiler ensures that there is at
most one anonymous type for a given sequence of property name/type pairs within each assembly. To
pass structures between assemblies you will need to properly define them.
Anonymous Types in C#
SpreadsheetGear: ASP.NET Excel Reporting
Easily create richly formatted Excel reports without Excel using the new generation of
spreadsheet technology built from the ground up for scalability and reliability. learn more
print?
01 class Employee
02 {
06 {
07 get
08 {
09 return _EmpID;
10 }
11 set
Aishwarya Lakshmi 37
C# Notes
12 {
13 _EmpID = value;
14 }
15 }
17 {
18 get
19 {
20 return _EmpName;
21 }
22 set
23 {
24 _EmpName = value;
25 }
26 }
27
28 }
print?
Note that the properties/ members are initialized here through object initializer .
An object initializer can specify values for one or more properties of an object.
class members such as methods or events are not allowed.
I can also create an object via Implicit type reference .
view source
print?
print?
print?
print?
C# Var Examples
Top of Form
dotnetperls.com Go
Bottom of Form
You are unfamiliar with the var keyword in the C# programming language
and want to look at an example of it with explanations. It doesn't seem to fit
with the rest of the language. This short information sheet has an example
of var along with some discussion, with code in the C# language.
Example
First, we look at some examples of using this new keyword in the C#
language. Here is a code example of the var keyword being used in three
different contexts. You need the .NET Framework 3.5 or a later version to
run this.
Aishwarya Lakshmi 40
C# Notes
using System;
using System.Collections.Generic;
using System.Linq;
class Program
// 1.
1,
2,
7,
};
// 2.
where (item % 2 == 1)
select item;
// 3.
Console.WriteLine(item);
Console.WriteLine(item);
Output
1
Aishwarya Lakshmi 42
C# Notes
Description of the program. It uses var and List. The variable cat is
known to be a List. Hover over the "var" keyword and the compiler will tell
you that it's a List. Here we see the var items query. It returns
"IEnumerable<int>". You can use the foreach loop with var. You can use the
var item exactly like you can use any type.
Type systems
The C# language is strongly-typed, which means that memory is labeled by
what kind of object it contains. The language uses strong types to enforce
code quality. Variables are both memory and also type annotations. It raises
errors and warnings because it wants your code to work properly. It makes
inferences about your code and can deduce the type of a variable without
you telling it exactly.
Brevity of the language. The C# programming language is wordy. We
don't like entering text at all. Languages like C# and Java sometimes have
very long keywords. You can reduce this with var, which allows a three-
letter type to be used.
Var limitations. Here we look at an interesting limitation of the var
keyword. You can't assign a new var to null. This will result in the CS0825
warning. You can't use var as a parameter type or a return value of a
method.
Intermediate language (IL)
Here we look at the internal implementation and behavior of the var
keyword in the C# language. IL is what C# code is turned into. You can see
it with a utility called IL Disassembler provided with Visual Studio. There are
two int32 values in the IL below.
var a = 5;
Aishwarya Lakshmi 43
C# Notes
int b = 5;
return a + b;
IL of the method
.maxstack 1
IL_0000: nop
IL_0001: ldc.i4.5
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: stloc.1
IL_0007: ldloc.1
IL_0008: ret
Summary
We saw how you can use the var keyword in the C# programming language.
Find out what it stands for by hovering over it in Visual Studio. It has
similarities to #define or typedef in C++. Use var for brevity and where it
makes the code easier to understand. The var keyword has equal
performance and does not affect runtime behavior in any way.
Ten LINQ Myths
Translations: English | Spanish
Here are ten root causes of the most common misunderstandings—distilled from
many hundreds of questions on the LINQ forums.
Myth #1
All LINQ queries must start with the ‘var’ keyword. In fact, the very
purpose of the ‘var’ keyword is to start a LINQ query!
The var keyword and LINQ queries are separate concepts. The purpose of var is to
let the compiler guess what type you want for a local variable declaration (implicit
typing). For example, the following:
var s = "Hello";
string s = "Hello";
You can see here that all that we're achieving with var is to abbreviate
IEnumerable<string>. Some people like this because it cuts clutter; others
argue that implicit typing can make it less clear what's going on.
Now, there are times when a LINQ query necessitates the use of var. This is when
projecting an anonymous type:
Here is an example of using an anonymous type outside the context of LINQ query:
Myth #2
All LINQ queries must use query syntax.
There are two kinds of syntax for queries: lambda syntax and query syntax (or
query comprehension syntax). Here's an example of lambda syntax:
Logically, the compiler translates query syntax into lambda syntax. This means
that everything that can be expressed in query syntax can also be expressed in
lambda syntax. Query syntax can be a lot simpler, though, with queries that
involve more than one range variable. (In this example, we used just a single range
variable, p, so the two syntaxes were similarly simple).
Not all operators are supported in query syntax, so the two syntax styles are
complementary. For the best of both worlds, you can mix query styles in a single
statement (see Myth #5 for an example).
Myth #3
Aishwarya Lakshmi 46
C# Notes
To retrieve all customers from the customer table, you must perform a
query similar to the following:
var query = from c in db.Customers select c;
The expression:
db.Customers
And this:
.Single();
Myth #4
To reproduce a SQL query in LINQ, you must make the LINQ query look
as similar as possible to the SQL query.
LINQ and SQL are different languages that employ very different concepts.
Possibly the biggest barrier in becoming productive with LINQ is the "thinking in
SQL" syndrome: mentally formulating your queries in SQL and then transliterating
them into LINQ. The result is that you're constantly fighting the API!
Once you start thinking directly in LINQ, your queries will often bear little
resemblance to their SQL counterparts. In many cases, they'll be radically simpler,
too.
Aishwarya Lakshmi 47
C# Notes
Myth #5
To do joins efficiently in LINQ, you must use the join keyword.
This is true, but only when querying local collections. When querying a database,
the join keyword is completely unnecessary: all ad-hoc joins can be accomplished
using multiple from clauses and subqueries. Multiple from clauses and subqueries
are more versatile too: you can also perform non-equi-joins.
Better still, in LINQ to SQL and Entity Framework, you can query association
properties, alleviating the need to join altogether! For instance, here's how to
retrieve the names and IDs of all customers who have made no purchases:
from c in db.Customers
where !c.Purchases.Any()
from c in db.Customers
Notice that we're mixing fluent and query syntax. See LINQPad for more examples
on association properties, manual joins, and mixed-syntax queries.
Myth #6
Because SQL emits flat result sets, LINQ queries must be structured to
emit flat result sets, too.
This is a consequence of Myth #4. One of LINQ's big benefits is that you can:
1. Query a structured object graph through association properties (rather than having
to manually join)
2. Project directly into object hierarchies
The two are independent, although 1 helps 2. For example, if you want to retrieve
the names of customers in the state of WA along with all their purchases, you can
simply do the following:
Aishwarya Lakshmi 48
C# Notes
from c in db.Customers
select new
c.Name,
The hierarchical result from this query is much easier to work with than a flat result
set!
We can achieve the same result without association properties as follows:
from c in db.Customers
select new
c.Name,
Myth #7
To do outer joins in LINQ to SQL, you must always use
DefaultIfEmpty().
This is true only if you want a flat result set. The examples in the preceding myth,
for instance, translate to a left outer join in SQL, and require no DefaultIfEmpty
operator.
Myth #8
Aishwarya Lakshmi 49
C# Notes
LINQ follows a lazy evaluation model, which means queries execute not when
constructed, but when enumerated. This means you can build up a query in as
many steps as you like, and it won't actually hit the server until you eventually
start consuming the results.
For instance, the following query retrieves the names of all customers whose name
starts with the letter 'A', and who have made at least two purchases. We build this
query in three steps:
Console.WriteLine (name);
Myth #9
A method cannot return a query, if the query ends in the 'new'
operator
The trick is to project into an ordinary named type with an object initializer:
return
from c in Customer
FirstName = c.FirstName,
Aishwarya Lakshmi 50
C# Notes
LastName = c.LastName
};
Myth #10
The best way to use LINQ to SQL is to instantiate a single DataContext
to a static property, and use that shared instance for the life of the
application.
This strategy will result in stale data, because objects tracked by a DataContext
instance are not refreshed simply by requerying.
Using a single static DataContext instance in the middle tier of a distributed
application will cause further trouble, because DataContext instances are not
thread-safe.
The correct approach is to instantiate fresh DataContext objects as required,
keeping DataContext instances fairly short-lived. The same applies with Entity
Framework.
Other Versions
Aishwarya Lakshmi 51
C# Notes
This topic gives a brief introduction to LINQ query expressions and some of the typical kinds of
operations that you perform in a query. More detailed information is in the following topics:
LINQ Query Expressions (C# Programming Guide)
Standard Query Operators Overview
Note
If you already are familiar with a query language such as SQL or XQuery, you can skip most of this
topic. Read about the "from clause" in the next section to learn about the order of clauses in LINQ
query expressions.
In a LINQ query, the first step is to specify the data source. In C# as in most programming languages a
variable must be declared before it can be used. In a LINQ query, the from clause comes first in order to
introduce the data source (customers) and the range variable (cust).
VB
C#
C++
F#
JScript
Copy
//queryAllCustomers is an IEnumerable<Customer>
Aishwarya Lakshmi 52
C# Notes
select cust;
The range variable is like the iteration variable in a foreach loop except that no actual iteration occurs in
a query expression. When the query is executed, the range variable will serve as a reference to each
successive element in customers. Because the compiler can infer the type of cust, you do not have to
specify it explicitly. Additional range variables can be introduced by a let clause. For more information,
see let clause (C# Reference).
Note
For non-generic data sources such as ArrayList, the range variable must be explicitly typed. For more
information, see How to: Query an ArrayList with LINQ and from clause (C# Reference).
Filtering
Probably the most common query operation is to apply a filter in the form of a Boolean expression. The
filter causes the query to return only those elements for which the expression is true. The result is
produced by using the where clause. The filter in effect specifies which elements to exclude from the
source sequence. In the following example, only those customers who have an address in London are
returned.
VB
C#
C++
F#
JScript
Aishwarya Lakshmi 53
C# Notes
Copy
select cust;
You can use the familiar C# logical AND and OR operators to apply as many filter expressions as
necessary in the where clause. For example, to return only customers from "London" AND whose name is
"Devon" you would write the following code:
VB
C#
C++
F#
JScript
Copy
To return customers from London or Paris, you would write the following code:
Aishwarya Lakshmi 54
C# Notes
VB
C#
C++
F#
JScript
Copy
Ordering
Often it is convenient to sort the returned data. The orderby clause will cause the elements in the
returned sequence to be sorted according to the default comparer for the type being sorted. For
example, the following query can be extended to sort the results based on the Name property. Because
Name is a string, the default comparer performs an alphabetical sort from A to Z.
VB
Aishwarya Lakshmi 55
C# Notes
C#
C++
F#
JScript
Copy
var queryLondonCustomers3 =
select cust;
To order the results in reverse order, from Z to A, use the orderby…descending clause.
For more information, see orderby clause (C# Reference).
Grouping
The group clause enables you to group your results based on a key that you specify. For example you
could specify that the results should be grouped by the City so that all customers from London or Paris
are in individual groups. In this case, cust.City is the key.
Note
The types are explicit in the following examples to illustrate the concept. You could also use implicit
typing for custQuery, group, and customer to let the compiler determine the exact type.
Aishwarya Lakshmi 56
C# Notes
VB
C#
C++
F#
JScript
Copy
var queryCustomersByCity =
Console.WriteLine(customerGroup.Key);
}
Aishwarya Lakshmi 57
C# Notes
When you end a query with a group clause, your results take the form of a list of lists. Each element in
the list is an object that has a Key member and a list of elements that are grouped under that key. When
you iterate over a query that produces a sequence of groups, you must use a nested foreach loop. The
outer loop iterates over each group, and the inner loop iterates over each group's members.
If you must refer to the results of a group operation, you can use the into keyword to create an identifier
that can be queried further. The following query returns only those groups that contain more than two
customers:
VB
C#
C++
F#
JScript
Copy
var custQuery =
orderby custGroup.Key
Aishwarya Lakshmi 58
C# Notes
select custGroup;
Joining
Join operations create associations between sequences that are not explicitly modeled in the data
sources. For example you can perform a join to find all the customers and distributors who have the
same location. In LINQ the join clause always works against object collections instead of database tables
directly.
VB
C#
C++
F#
JScript
Copy
var innerJoinQuery =
In LINQ you do not have to use join as often as you do in SQL because foreign keys in LINQ are
represented in the object model as properties that hold a collection of items. For example, a Customer
object contains a collection of Order objects. Rather than performing a join, you access the orders by
using dot notation:
Copy
Selecting (Projections)
The select clause produces the results of the query and specifies the "shape" or type of each returned
element. For example, you can specify whether your results will consist of complete Customer objects,
just one member, a subset of members, or some completely different result type based on a
computation or new object creation. When the select clause produces something other than a copy of
the source element, the operation is called a projection. The use of projections to transform data is a
powerful capability of LINQ query expressions. For more information, see Data Transformations with LINQ
(C#) and select clause (C# Reference).
Other Versions
Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of
query capabilities directly into the C# language (also in Visual Basic and potentially any other .NET
language). With LINQ, a query is now a first-class language construct, just like classes, methods, events
and so on.
For a developer who writes queries, the most visible "language-integrated" part of LINQ is the query
expression. Query expressions are written in a declarative query syntax introduced in C# 3.0. By using
query syntax, you can perform even complex filtering, ordering, and grouping operations on data
sources with a minimum of code. You use the same basic query expression patterns to query and
transform data in SQL databases, ADO.NET Datasets, XML documents and streams, and .NET collections.
The following example shows the complete query operation. The complete operation includes creating a
data source, defining the query expression, and executing the query in a foreach statement.
Aishwarya Lakshmi 60
C# Notes
VB
C#
C++
F#
JScript
Copy
class LINQQueryExpressions
IEnumerable<int> scoreQuery =
select score;
Aishwarya Lakshmi 61
C# Notes
// Output: 97 92 81
For more information about the basics of LINQ in C#, see Getting Started with LINQ in C#.
• Query expressions can be used to query and to transform data from any LINQ-enabled data
source. For example, a single query can retrieve data from a SQL database, and produce an XML
stream as output.
• Query expressions are easy to master because they use many familiar C# language constructs.
For more information, see Getting Started with LINQ in C#.
• The variables in a query expression are all strongly typed, although in many cases you do not have
to provide the type explicitly because the compiler can infer it. For more information, see Type
Relationships in LINQ Query Operations (C#).
• A query is not executed until you iterate over the query variable in a foreach statement. For more
information, see Introduction to LINQ Queries (C#).
• At compile time, query expressions are converted to Standard Query Operator method calls
according to the rules set forth in the C# specification. Any query that can be expressed by using
query syntax can also be expressed by using method syntax. However, in most cases query syntax
is more readable and concise. For more information, see C# Language Specification and Standard
Query Operators Overview.
• As a rule when you write LINQ queries, we recommend that you use query syntax whenever
possible and method syntax whenever necessary. There is no semantic or performance difference
between the two different forms. Query expressions are often more readable than equivalent
expressions written in method syntax.
• Some query operations, such as Count or Max, have no equivalent query expression clause and
must therefore be expressed as a method call. Method syntax can be combined with query syntax
in various ways. For more information, see LINQ Query Syntax versus Method Syntax (C#).
• Query expressions can be compiled to expression trees or to delegates, depending on the type
that the query is applied to. IEnumerable<T> queries are compiled to delegates. IQueryable and
Aishwarya Lakshmi 62
C# Notes
IQueryable<T> queries are compiled to expression trees. For more information, see Expression
Trees (C# and Visual Basic).
Other Versions
A lambda expression is an anonymous function that can contain expressions and statements, and can be
used to create delegates or expression tree types.
All lambda expressions use the lambda operator =>, which is read as "goes to". The left side of the
lambda operator specifies the input parameters (if any) and the right side holds the expression or
statement block. The lambda expression x => x * x is read "x goes to x times x." This expression can be
assigned to a delegate type as follows:
VB
C#
C++
F#
JScript
Copy
VB
C#
C++
F#
JScript
Copy
using System.Linq.Expressions;
namespace ConsoleApplication1
class Program
{
Aishwarya Lakshmi 64
C# Notes
The => operator has the same precedence as assignment (=) and is right-associative.
Lambdas are used in method-based LINQ queries as arguments to standard query operator methods
such as Where.
When you use method-based syntax to call the Where method in the Enumerable class (as you do in
LINQ to Objects and LINQ to XML) the parameter is a delegate type System.Func<T, TResult>. A lambda
expression is the most convenient way to create that delegate. When you call the same method in, for
example, the System.Linq.Queryable class (as you do in LINQ to SQL) then the parameter type is
an System.Linq.Expressions.Expression<Func> where Func is any Func delegates with up to sixteen
input parameters. Again, a lambda expression is just a very concise way to construct that expression
tree. The lambdas allow the Where calls to look similar although in fact the type of object created from
the lambda is different.
In the previous example, notice that the delegate signature has one implicitly-typed input parameter of
type int, and returns an int. The lambda expression can be converted to a delegate of that type because
it also has one input parameter (x) and a return value that the compiler can implicitly convert to type int.
(Type inference is discussed in more detail in the following sections.) When the delegate is invoked by
using an input parameter of 5, it returns a result of 25.
Lambdas are not allowed on the left side of the is or as operator.
All restrictions that apply to anonymous methods also apply to lambda expressions. For more
information, see Anonymous Methods (C# Programming Guide).
Expression Lambdas
A lambda expression with an expression on the right side is called an expression lambda. Expression
lambdas are used extensively in the construction of Expression Trees (C# and Visual Basic). An
expression lambda returns the result of the expression and takes the following basic form:
Copy
The parentheses are optional only if the lambda has one input parameter; otherwise they are required.
Two or more input parameters are separated by commas enclosed in parentheses:
Copy
(x, y) => x == y
Sometimes it is difficult or impossible for the compiler to infer the input types. When this occurs, you can
specify the types explicitly as shown in the following example:
Copy
Copy
() => SomeMethod()
Note in the previous example that the body of an expression lambda can consist of a method call.
However, if you are creating expression trees that will be consumed in another domain, such as SQL
Server, you should not use method calls in lambda expressions. The methods will have no meaning
outside the context of the .NET common language runtime.
Statement Lambdas
A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:
Copy
The body of a statement lambda can consist of any number of statements; however, in practice there
are typically no more than two or three.
Copy
myDel("Hello");
Statement lambdas, like anonymous methods, cannot be used to create expression trees.
Many Standard query operators have an input parameter whose type is one of the Func<T, TResult>
family of generic delegates. The Func<T, TResult> delegates use type parameters to define the number
and type of input parameters, and the return type of the delegate. Func delegates are very useful for
encapsulating user-defined expressions that are applied to each element in a set of source data. For
example, consider the following delegate type:
Copy
The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is
the return value. The return value is always specified in the last type parameter. Func<int, string,
bool> defines a delegate with two input parameters, int and string, and a return type of bool. The
following Func delegate, when it is invoked, will return true or false to indicate whether the input
parameter is equal to 5:
Copy
You can also supply a lambda expression when the argument type is an Expression<Func>, for
example in the standard query operators that are defined in System.Linq.Queryable. When you specify
an Expression<Func> argument, the lambda will be compiled to an expression tree.
A standard query operator, the Count method, is shown here:
Copy
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
The compiler can infer the type of the input parameter, or you can also specify it explicitly. This
particular lambda expression counts those integers (n) which when divided by two have a remainder of
1.
The following method will produce a sequence that contains all the elements in the numbers array that
are to the left of the 9, because that is the first number in the sequence that does not meet the
condition:
Copy
This example shows how to specify multiple input parameters by enclosing them in parentheses. The
method returns all the elements in the numbers array until a number is encountered whose value is less
than its position. Do not confuse the lambda operator (=>) with the greater than or equal operator (>=).
Copy
When writing lambdas, you often do not have to specify a type for the input parameters because the
compiler can infer the type based on the lambda body, the underlying delegate type, and other factors
as described in the C# Language Specification. For most of the standard query operators, the first input
is the type of the elements in the source sequence. So if you are querying an
IEnumerable<Customer>, then the input variable is inferred to be a Customer object, which means
you have access to its methods and properties:
Copy
Lambdas can refer to outer variables that are in scope in the enclosing method or type in which the
lambda is defined. Variables that are captured in this manner are stored for use in the lambda
expression even if variables would otherwise go out of scope and be garbage collected. An outer variable
must be definitely assigned before it can be consumed in a lambda expression. The following example
demonstrates these rules:
Copy
class Test
D del;
D2 del2;
int j = 0;
// Demonstrate value of j:
// Output: j = 0
// Output: j = 10 b = True
test.TestMethod(5);
// Output: True
Console.WriteLine(result);
Console.ReadKey();