TDDD49 Programmering C# och .NET Lecture 3 - 2015 In this lecture:

advertisement
TDDD49
Programmering C# och .NET
Lecture 3 - 2015
Johannes Schmidt, Department of Computer and Information Science (IDA), Linköping University
In this lecture:
●
Anonymous types
●
Collections
●
LINQ
Anonymous types
Declare implicitly typed variables with var.
The type will be determined by the compiler.
var Record = new { ID = 225,
Name = "CSJR",
Description = "This is a record" };
var Employees
no1 = new
no2 = new
no3 = new
no4 = new
};
= new
{Name
{Name
{Name
{Name
{
=
=
=
=
"Harald", Age = 34},
"Charlie", Age = 31},
"Alice", Age = 54},
"Bob", Age = 20}
Console.WriteLine(Employees.no1.Name);
Anonymous type != undefined type
A variable declared as var has a very well-defined type. The type is
determined by the compiler, but is otherwise fixed and well-specified.
var Record1 = new {
Name = "Program",
Age = 42 };
var Record2 = new {
Name = "Donner",
Age = 7 };
var Record3 = new {
FirstName = "Tubo",
Age
= 77 };
var Record4 = new {
Age = 101,
Name = "Voix" };
Record2 = Record1;
Record2 = Record3;
Record2 = Record4;
// ok, same type
// Err: Cannot convert AnonymousType#2 to AnonymousType#1
// Err: Cannot convert AnonymousType#3 to AnonymousType#1
Anonymous types as parameter types?
A variable declared as var can only be passed as a parameter to a
method if the method's parameter type is object or if we use
method type inference:
public static void method(var parameter) {
Console.WriteLine(parameter); }
// does not work/compile!
public static void methodA(object parameter) { // works
Console.WriteLine(parameter); }
public static void methodB<T>(T parameter) {
Console.WriteLine(parameter); }
var Record1 = new {
methodA(Record1);
methodB(Record1);
// works, preferred
Name = "Program",
Age = 42 };
// works
// works, preferred since type safer
When to use Anonymous types
Rule of Thumb: avoid anonymous types.
Use them only when the type is clear from the context, and where
it increases code readability.
// good example:
// write
var items = Dictionary<string, List<Account>>();
// instead of
Dictionary<string, List<Account>> items = Dictionary<string, List<Account>>();
// bad example:
var result = getData();
Anonymous types are particularly important when it comes to aggregation
of data from multiple types (i.e. LINQ, see later on).
What is a Collection?
Anything that implements
System.Collections.IEnumerable or
System.Collections.Generic.IEnumerable<T>.
These interfaces allow to iterate over the collection (e.g. with foreach).
Also ordinary arrays count as Collection.
That is:
Arrays + all classes from System.Collections and System.Collections.Generic:
Ordinary array +
ArrayList
BitArray
Dictionary
SortedDictionary
SortedList
LinkedList
List
Queue
Stack
SortedSet
…
foreach on ordinary arrays
int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
foreach (int item in array)
{
Console.WriteLine(item);
}
// translates by the compiler to
for(int counter = 0; counter < array.Length; counter++)
{
int item = array[counter];
Console.WriteLine(item);
}
foreach on real Collections
Every collection implements the interface
System.Collections.Generic.IEnumerator<T> or
System.Collections.IEnumerator
This provides the method GetEnumerator() which delivers an IEnumerator and with it the
method MoveNext() and the property Current.
var stack = new System.Collections.Generic.Stack<int>();
foreach (int item in stack)
{
Console.WriteLine(item);
}
// translates by the compiler to
System.Collections.Generic.Stack<int>.Enumerator enumerator;
enumerator = stack.GetEnumerator();
while(enumerator.MoveNext())
{
int item = enumerator.Current;
}
Console.WriteLine(item);
Collection initialisers
List<string> MyDictionary;
// write
MyDictionary = new List<string>() {
"Ice",
"Equipement",
"Sea",
"Goofy"
};
// instead of
MyDictionary.Add("Ice");
MyDictionary.Add("Equipement");
MyDictionary.Add("Sea");
MyDictionary.Add("Goofy");
// (this is what the comipler does then for you)
Available whenever the .Add() method is available
(this excludes e.g. Stacks and Queues).
LINQ
LINQ = Language Integrated Query Language
In C# any collection can be queried with standard query operators
(in database terms, a collection is just a database).
An SQL-like syntax is available.
A LINQ query consists of three parts:
// 1. Define/get data source.
int[] numbers = new int[7] { 41, 24, 16, 7, 10, 2, 17, 38, 58 };
// 2. create query
IEnumerable<int> numQuery =
from num in numbers
where (num < 38)
select num;
// 3. excecute query
foreach (int num in numQuery)
{
Console.Write(num + " ");
}
Data source
public class Person
{
public string Name;
public int Age;
public long DepartmentID;
public void Display()
{
Console.WriteLine("Name: " + Name + "\tAge: " + Age + "\tDep: " + DepartmentID);
}
}
var
var
var
var
var
Person1
Person2
Person3
Person4
Person5
=
=
=
=
=
new
new
new
new
new
Person()
Person()
Person()
Person()
Person()
{
{
{
{
{
Name
Name
Name
Name
Name
=
=
=
=
=
"Harald",
"Hanne",
"Harald",
"Alice",
"Bob",
Age
Age
Age
Age
Age
=
=
=
=
=
45,
32,
22,
28,
37,
DepartmentID
DepartmentID
DepartmentID
DepartmentID
DepartmentID
=
=
=
=
=
0
1
2
1
4
};
};
};
};
};
var MyList = new List<Person>() {Person1, Person2, Person3, Person4, Person5};
Filtering with Where()
IEnumerable<Person> WhereData = MyList.Where(x => x.Age < 29);
foreach (Person x in WhereData)
{
x.Display();
}
Output:
Name: Harald
Name: Alice
Age: 22
Age: 28
Dep: 2
Dep: 1
// You can also define and excecute the query in one step:
foreach (var x in MyList.Where(x => x.Age < 29))
{
x.Display();
}
Projecting with Select()
// select parts and change type with Select
IEnumerable<double> SelectData = MyList.Select(x => (double)x.Age * 1.5);
foreach (double x in SelectData)
{
Console.Write(x + " ");
}
Output:
67.5 48 33 42 55.5
Projecting with Select()
var SelectData = MyList.Select(x =>
new
{
Name = x.Name,
Sex = getSex(x)
});
foreach (var item in SelectData)
{
Console.Writeln(item);
}
Output:
{Name =
{Name =
{Name =
{Name =
{Name =
Harald, Sex = m}
Hanne, Sex = f}
Harald, Sex = m}
Alice, Sex = f}
Bob, Sex = m}
Count with Count()
// count all elements
Console.WriteLine( MyList.Count() );
// count only those between 25 and 40
Console.WriteLine( MyList.Where(x => x.Age > 25 && x.Age < 40).Count() );
// the same, but more elegant
Console.WriteLine( MyList.Count(x => x.Age > 25 && x.Age < 40) );
Output:
5
3
3
Deferred execution
A query is only executed when necessary.
That is, usually when iterating over it with a foreach statement.
IEnumerable<int> data = MyList.Select(x => { Console.Write("Et voila ");
return x.Age; });
Console.WriteLine("Foreach 1");
foreach (int x in data)
{
Console.WriteLine(x);
}
Output:
Foreach 1
Et voila 45
Et voila 32
Et voila 22
Et voila 28
Et voila 37
Deferred execution
A query is only executed when necessary.
That is, usually when iterating over it with a foreach statement.
IEnumerable<int> data = MyList.Select(x => { Console.Write("Et voila ");
return x.Age; });
Console.WriteLine("Foreach 1");
foreach (int x in data)
{
Console.WriteLine(x);
}
Console.WriteLine("Foreach 2");
foreach (int x in data)
{
Console.WriteLine(x);
}
Console.WriteLine("Foreach 3");
foreach (int x in data)
{
Console.WriteLine(x);
}
Output:
Foreach 1
Et voila 45
Et voila 32
Et voila 22
Et voila 28
Et voila 37
Foreach 2
Et voila 45
Et voila 32
Et voila 22
Et voila 28
Et voila 37
Foreach 3
Et voila 45
Et voila 32
Et voila 22
Et voila 28
Et voila 37
Enforce execution
Execution can also be enforced with ToArray, ToList, ToDictionary
IEnumerable<int> data = MyList.Select(x => { Console.Write("Et voila ");
return x.Age; }).ToList();
Console.WriteLine("Foreach 1");
foreach (int x in data)
{
Console.WriteLine(x);
}
Console.WriteLine("Foreach 2");
foreach (int x in data)
{
Console.WriteLine(x);
}
Console.WriteLine("Foreach 3");
foreach (int x in data)
{
Console.WriteLine(x);
}
Output:
Et voila Et voila Et voila Et voila Et voil
Foreach 1
45
32
22
28
37
Foreach 2
45
32
22
28
37
Foreach 3
45
32
22
28
37
Deferred execution b)
A query is only executed when necessary.
That is, usually when iterating over it with a foreach statement.
IEnumerable<int> Data = MyList.Select(x => x.Age);
Console.WriteLine("Executing:");
foreach (int x in Data) {
Console.Write(x + " ");
}
Console.WriteLine();
// modify data
MyList.Remove(Person3);
MyList.Remove(Person4);
// myList has changed...
Console.WriteLine("Executing again:");
foreach (int x in Data) {
Console.Write(x + " ");
}
Output:
Executing:
45 32 22 28 37
Executing again:
45 32 37
Enforce execution b)
Execution can also be enforced with ToArray, ToList, ToDictionary
IEnumerable<int> Data = MyList.Select(x => x.Age);
Console.WriteLine("Executing:");
foreach (int x in Data) {
Console.Write(x + " ");
}
Console.WriteLine();
// enforce execution and take a copy
IEnumerable<int> Data2 = Data.ToList();
// modify data
MyList.Remove(Person3);
MyList.Remove(Person4);
Output:
Executing:
45 32 22 28 37
Executing again:
45 32 22 28 37
// myList has changed...
// but we took a copy of the already executed query
Console.WriteLine("Executing again:");
foreach (int x in Data2) {
Console.Write(x + " ");
}
Order with OrderBy()
Also hierarchical ordering is possible, with ThenBy()
// Order with OrderBy()
IEnumerable<Person> OrderedData =
MyList.OrderBy(x => x.Name);
foreach (Person x in OrderedData) {
x.Display();
}
// Order with OrderBy() and then ThenBy()
IEnumerable<Person> OrderedDataB =
MyList.OrderBy(x => x.Name)
.ThenBy(x => x.Age);
foreach (Person x in OrderedDataB) {
x.Display();
}
// Order with OrderByDescending()
IEnumerable<Person> OrderedDataC =
MyList.OrderByDescending(x => x.Name);
foreach (Person x in OrderedDataC) {
x.Display();
}
Output:
Alice
Bob
Hanne
Harald
Harald
28
37
32
45
22
Alice
Bob
Hanne
Harald
Harald
28
37
32
22
45
Harald
Harald
Hanne
Bob
Alice
22
45
32
37
28
Additional data
public class Department
{
public long ID;
public string Name;
public void Display()
{
Console.WriteLine("ID: " + ID + "\tName: " + Name);
}
}
var
var
var
var
var
Dep1
Dep2
Dep3
Dep4
Dep5
=
=
=
=
=
new
new
new
new
new
Department()
Department()
Department()
Department()
Department()
{
{
{
{
{
ID
ID
ID
ID
ID
=
=
=
=
=
0,
1,
2,
3,
4,
Name
Name
Name
Name
Name
=
=
=
=
=
"IDA"
"IFM"
"IKK"
"MAI"
"ISY"
};
};
};
};
};
var DepList = new List<Department>() { Dep1, Dep2, Dep3, Dep4, Dep5};
All data, summary
var
var
var
var
var
Person1
Person2
Person3
Person4
Person5
=
=
=
=
=
new
new
new
new
new
Person()
Person()
Person()
Person()
Person()
{
{
{
{
{
Name
Name
Name
Name
Name
=
=
=
=
=
"Harald",
"Hanne",
"Harald",
"Alice",
"Bob",
Age
Age
Age
Age
Age
=
=
=
=
=
45,
32,
22,
28,
37,
DepartmentID
DepartmentID
DepartmentID
DepartmentID
DepartmentID
=
=
=
=
=
0
1
2
1
4
};
};
};
};
};
var MyList = new List<Person>() {Person1, Person2, Person3, Person4, Person5};
var
var
var
var
var
Dep1
Dep2
Dep3
Dep4
Dep5
=
=
=
=
=
new
new
new
new
new
Department()
Department()
Department()
Department()
Department()
{
{
{
{
{
ID
ID
ID
ID
ID
=
=
=
=
=
0,
1,
2,
3,
4,
Name
Name
Name
Name
Name
=
=
=
=
=
"IDA"
"IFM"
"IKK"
"MAI"
"ISY"
};
};
};
};
};
var DepList = new List<Department>() { Dep1, Dep2, Dep3, Dep4, Dep5};
Join with Join()
var items = MyList.Join(
DepList,
person => person.DepartmentID,
dep => dep.ID,
(person, dep) => new {
//
//
//
//
Collection that shall be joined with
select key1 (to match key2)
select key2
create the new joined data
Name = person.Name,
Age = person.Age,
DepartmentID = person.DepartmentID,
DepartmentID2 = dep.ID,
// ID2 just for illustration purpose
DepartmentName = dep.Name});
foreach (var x in items){
Console.WriteLine("Name: " + x.Name + "\tAge: " + x.Age
+ "\tDep: " + x.DepartmentID + "\tDep2: " + x.DepartmentID2
+ "\tDepName: " + x.DepartmentName);
}
Output:
Name:
Name:
Name:
Name:
Name:
Harald
Hanne
Harald
Alice
Bob
Age:
Age:
Age:
Age:
Age:
45
32
22
28
37
Dep:
Dep:
Dep:
Dep:
Dep:
0
1
2
1
4
Dep2:
Dep2:
Dep2:
Dep2:
Dep2:
0
1
2
1
4
DepName:
DepName:
DepName:
DepName:
DepName:
IDA
IFM
IKK
IFM
ISY
And many more
GroupBy
OfType
Union
Concat
Intersect
Distinct
Except
SequenceEquals
Reverse
SelectMany
GroupJoin
...
-
group by some criteria
get only items of a certain type
union without duplicates
union (duplicates possible)
intersection
get rid of duplicates
set minus
check for equivalence, including the order
reverse the order
resolve collections of collections
similar to Join
On numeric values: Max, Min, Sum, Average
LINQ query expressions
You can use an alternative syntax with keywords.
With query expressions the syntax can be SQL-like.
Start with from … in … and close with select …
You can combine both syntaxes.
int[] numbers = new int[7] { 41, 24, 16, 7, 10, 2, 17, 38, 58 };
// instead of
var numQuery = numbers.Where(num => num < 38);
// write
var numQuery =
from num in numbers
where (num < 38)
select num;
LINQ query expressions
// instead of
var newData = MyList.Where(person => person.Age < 38).Select(person
=> new { person.Name, person.Age });
// write
var newData =
from person in MyList
where (person.Age < 38)
select new {person.Name, person.Age};
foreach (var x in newData)
{
Console.WriteLine(x);
}
Output:
{Name =
{Name =
{Name =
{Name =
Hanne, Age = 32}
Harald, Age = 22}
Alice, Age = 28}
Bob, Age = 37}
LINQ query expressions
let – create a local variable in a query expression
var newData =
from person in MyList
where (person.Age < 38)
select new { person.Name, person.Age };
// equivalent
var newData =
from person in MyList
let Age = person.Age
where (Age < 38)
select new { person.Name, Age };
into – continue a query in a query expression
(use the output of a query as the input of another query)
flattening – use multiple from clauses to achieve SelectMany
See LINQ on msdn for further details and examples.
What to do with LINQ
Transform and filter data in a uniform way, independently of its source or form.
●
●
●
●
LINQ to Objects (IEnumerable Collections)
LINQ to SQL (access SQL databases via LINQ)
LINQ to XML (query and modify XML documents via LINQ)
LINQ to DataSet (cached data from different sources, see ADO.NET)
Links and Literature
Essential C# 5.0 by Mark Michaelis
https://msdn.microsoft.com/en-us/library/bb397926.aspx
LINQ
http://msdn.microsoft.com/en-us/library/bb397919.aspx
LINQ to Objects
http://msdn.microsoft.com/en-us/library/bb386976.aspx
LINQ to SQL
http://msdn.microsoft.com/en-us/library/bb387098.aspx
LINQ to XML
http://msdn.microsoft.com/en-us/library/bb386977.aspx
LINQ to DataSet
https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
101 LINQ samples
Download