LINQ
LINQ (Abbreviation for Language Integrated Query ; pronunciation link ) is a programmatic method from Microsoft for accessing data. LINQ was developed by Erik Meijer and appeared for the first time with .NET Framework 3.5.
Aim of LINQ
The data that a program accesses comes from different sources. This includes
- internal sources such as fields and object lists and hierarchies;
- external sources such as XML documents, database tables, text files, Excel files, e-mail messages, SharePoint lists and many others.
Each of these data sources has its own access methods. This means that the programmer has to deal with the details of the respective method in each individual case. Furthermore, the program must be changed every time data is moved from one source to a source of a different type.
LINQ tries to eliminate this problem by providing a uniform method for any data access within the .NET development platform. The syntax of the queries in LINQ is similar to that of SQL . In contrast to SQL, however, LINQ also provides language elements that are suitable for accessing hierarchical and network structures by using the relationships that exist there.
Working method
LINQ is a collection of extension methods that operate on monads . In addition, some .NET languages such as C # , VB.NET and F # have their own keywords for a predetermined number of LINQ methods. Monads are represented in .NET as generic classes or interfaces with a single type argument (e.g. , ).
IEnumerable<T>
IObservable<T>
LINQ instructions are directly embedded as source code in .NET programs. Thus the code can be checked for errors by the compiler . Other methods such as ADO and ODBC, however, use query strings. These can only be interpreted at runtime; then errors have a more serious effect and are more difficult to analyze.
Within the source program in C # or VB.NET, LINQ presents the query results as strictly typed lists. It thus guarantees type safety at compilation time.
So-called LINQ providers translate the LINQ instructions into the special access methods of the respective data source. The following providers, among others, are available within the .NET platform:
- LINQ to Objects for accessing object lists and hierarchies in memory
- LINQ to SQL for querying and processing data in MS-SQL databases
- LINQ to Entities for querying and processing data in the relational model of ADO.NET ;
- LINQ to XML for accessing XML content
- LINQ to DataSet for accessing ADO.NET data collections and tables
- LINQ to SharePoint for access to SharePoint data.
Important concepts
The examples are in C # unless otherwise noted .
Delayed evaluation
LINQ expressions are not executed when they are defined, but when the value is queried. This is known as lazy evaluation (also deferred evaluation ). This means that the query can also be used multiple times.
var numbers = new List<int>() {1,2,3,4}; // list with 4 numbers
// query is defined but not evaluated
var query = from x in numbers
select x;
numbers.Add(5); // add a 5th number
// now the query gets evaluated
Console.WriteLine(query.Count()); // 5
numbers.Add(6); // add a 6th number
Console.WriteLine(query.Count()); // 6
The delayed evaluation can be implemented in different ways. For example, LINQ to Objects uses delegates , while LINQ to SQL implements the interface instead . To prevent the change in the result of the query, it must in another type convert (English: conversion ) are. This purpose is served conversion methods such as , , , , etc.
IQueryable<T>
AsEnumerable()
ToArray()
ToList()
ToDictionary()
ToLookup()
If the LINQ query calls a function that requires exception handling, the try-catch block must enclose the use of the query and not its creation.
Resolution of extension methods
LINQ functions as extension methods (English: extension method ) implemented. A list of elements of one type is given:
Using an extension method, the filtering method can now be (re-) implemented according to any criteria:
Where()
public static class EnumerableExtensions
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
foreach (var element in source)
{
if (predicate(element)) yield return element;
}
}
}
Certain .NET languages have their own keywords to call the methods:
var query =
from e in employees
where e.DepartmentId == 5
select e;
The compiler resolves these keywords into the corresponding method calls:
var query = employees.Where(e => e.DepartmentId == 5).Select(e => e);
Since these are extension methods, the compiler has to resolve the method calls into a call to the methods of the appropriate extension class:
var query = Enumerable.Select(EnumerableExtensions.Where(employees, e => e.DepartmentId == 5), e => e);
Important operators
From
From defines the data source of a query ( query ) or subquery ( subquery ), and a variable range ( range variable ) is a single element of the data source ( data source represented).
from rangeVariable in dataSource
// ...
Queries can have multiple from operations to allow joins from multiple data sources. It should be noted here that the join condition for multiple from operations is defined by the data structure and differs from the concept of a join in relational databases.
var queryResults =
from c in customers
from o in orders
select new { c.Name, o.OrderId, o.Price };
or shorter:
var queryResults =
from c in customers, o in orders
select new { c.Name, o.OrderId, o.Price };
Where
Where defines a filter on the data to be selected.
var queryResults =
from c in customers
from o in orders
where o.Date > DateTime.Now - TimeSpan.FromDays(7)
select new { c.Name, o.OrderId, o.Price };
Select
Select defines a projection or the form of the result of the LINQ query.
Often a subset of properties is projected using anonymous classes (i.e. new { …, … }
) or, from C # 7.0 onwards, also value tuples ( (…, …)
).
Group
Group is used to group elements according to a certain key:
var groupedEmployees =
from e in Employees
group e by e.Department; // group by department
An anonymous type made up of several keys can also be used as the key:
var groupedEmployees =
from e in Employees
group e by new { e.Department , e.Age }; // group by department and age
Into
Into can be used to store the result of a select , group or join operation in a temporary variable.
var groupedEmployees =
from e in Employees
group e by e.Department into EmployeesByDepartment
select new { Department = EmployeesByDepartment.Key, EmployeesByDepartment.Count() };
OrderBy and ThenBy
OrderBy and ThenBy is used to sort a list of items in ascending order.
var groupedEmployees =
from e in Employees
orderby e.Age // order employees by age; youngest first
thenby e.Name // order same-age employees by name; sort A-to-Z
select e;
With the help of OrderByDescending and ThenByDescending the list is sorted in descending order:
var groupedEmployees =
from e in Employees
orderby e.Age descending // oldest first
thenby e.Name descending // sort Z-to-A
select e;
Reverse
Reverse reverses the order of the elements.
Join
Join enables inner joins , group joins and left outer joins .
- Inner join
- An inner join maps the outer data source to the inner data source and returns a "flat" result. Elements of the outer data source for which there is no matching element of the inner data source are discarded.
var productCategories =
from c in categories // outer datasource
join p in products // inner datasource
on c.CategoryId equals p.CategoryId // categories without products are ignored
select new { c.CategoryName, p.ProductName };
- Group join
- A group join creates a hierarchical result set. The elements of the inner data source are grouped with the corresponding elements of the outer data source. Elements for which there is no corresponding element of the external data source are connected with an empty array.
var productCategories =
from c in categories
join p in products
on c.CategoryId equals p.CategoryId
into productsInCategory
select new { c.CategoryName, Products = productsInCategory };
- A group join can not be mapped in SQL because SQL does not allow a hierarchical result set. VB.NET has its own keyword with Group Join .
- Left outer join
- A left outer join maps the outer data source to the inner data source and returns a "flat" result. Elements of the outer data source for which there is no matching element of the inner data source are given a default value. To define the default value, the extension method is used, which converts empty enumerations into a single element enumeration with a default value:
DefaultIfEmpty()
var productCategories =
from c in categories
join p in products
on c.CategoryId equals p.CategoryId
into productsInCategory
from pic in productsInCategory.DefaultIfEmpty(
new Product(CategoryId = 0, ProductId = 0, ProductName = String.Empty))
select new { c.CategoryName, p.ProductName };
Let
Let enables the result of a partial query to be saved in a variable so that it can be used later in the query.
var ordersByProducts =
from c in categories
join p in products
on c.CategoryId equals p.CategoryId
into productsByCategory
let ProductCount = productsByCategory.Count()
orderby ProductCount
select new { c.CategoryName, ProductCount };
Any
Any is used to determine whether a sequence is empty or contains a specific predicate.
bool containsAnyElements = Enumerable.Empty<int>().Any(); // false
bool containsSix = Enumerable.Range(1,10).Any(x => x == 6); // true
Contains
Contains is used to determine whether a certain value is contained in a sequence.
bool containsSix = Enumerable.Range(1,10).Contains(6); // true
Skip and Take
Skip is used to skip a certain number of elements in a sequence. Take is used to select a maximum number of elements in a sequence.
IEnumerable<int> Numbers = Enumerable.Range(1,10).Skip(2).Take(5); // {3,4,5,6,7}
In addition, the extension methods and are defined for which separate keywords are defined in VB.NET. These methods allow the use of a predicate which defines which elements are skipped or selected.
SkipWhile()
TakeWhile()
Distinct
Distinct is used to select unique elements of a sequence.
IEnumerable<int> MultipleNumbers = new List<int>() {0,1,2,3,2,1,4};
IEnumerable<int> DistinctNumbers = MultipleNumbers.Distinct(); // {0,1,2,3,4}
Union, Intersect and Except
The set operators Union, Intersect and Except can be used for a list of elements:
var NumberSet1 = {1,5,6,9};
var NumberSet2 = {4,5,7,11};
var union = NumberSet1.Union(NumberSet2); // 1,5,6,9,4,7,11
var intersect = NumberSet1.Intersect(NumberSet2); // 5
var except = NumberSet1.Except (NumberSet2); // 1,6,9
Aggregates
Aggregate is used to apply an aggregate function to a data source.
var nums = new[]{1,2,3,4,5};
var sum = nums.Aggregate( (a,b) => a + b); // sum = 1+2+3+4+5 = 15
In addition, important aggregate functions are predefined. Predefined aggregate functions are about , , , , and .
Count()
LongCount()
Sum()
Min()
Max()
Average()
Zip
Zip combines two sequences together until one sequence ends.
1 IEnumerable<string> Days = new List<string>() { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
2 IEnumerable<int> Numbers = Enumerable.Range(1,10); // {1,2,3,4,5,6,7,8,9,10}
3 // Numbers 8..10 will be ignored
4 IEnumerable<string> NumberedDays = Days.Zip(Numbers, (day, number) => String.Format("{0}:{1}", number, day) ); // {"1:Monday", "2:Tuesday", ..., "7:Sunday"}
Concat
Concat appends another sequence of the same type to a sequence.
Sequence Equal
SequenceEqual checks whether two sequences are the same length and whether the elements are the same at the respective position of the corresponding sequences. Either the interface, the method of or the method is queried for comparison .
IEqualityComparer<T>
Equals()
TSource
GetHashCode()
SelectMany
SelectMany is essentially used to flatten a hierarchy. SelectMany works here as the bind operator >>=
, even shovel ( shovel called) in Haskell .
class Book
{
public string Title { get; set; }
public List<Author> Authors { get; set; }
}
class Author
{
public string Name { get; set; }
}
class Foo
{
public IEnumerable<string> GetAuthorsFromBooks(IEnumerable<Book> books)
{
// Input-Monad: Enumerable Book Author
// Output-Monad: Enumerable Author
return books.SelectMany( book => book.Authors);
}
}
A typical use case for flattening a hierarchy is to list all files in a directory as well as the subdirectories of the directory.
IEnumerable<string> GetFilesInSubdirectories(string rootDirectory)
{
var directoryInfo = new DirectoryInfo(rootDirectory); // get the root directory
return directoryInfo.GetDirectories() // get directories in the root directory
.SelectMany(dir => GetFilesInSubdirectories(dir.FullName)) // recursively flattening the hierarchy of directories
.Concat(directoryInfo.GetFiles().Select(file => file.FullName)); // get the file name for each file in the directories
}
Scalar selectors
LINQ defines different selectors for scalar results:
method | Result |
---|---|
ElementAt(n) |
Returns the nth element if the query returns one or more results. Throws an exception if fewer than n results are returned. |
ElementAtOrDefault(n) |
Returns the nth element if the query returns one or more results. Returns the default value if fewer than n results are returned. |
First() |
Returns the first element if the query returns one or more results. Throws an exception if no results are returned. |
FirstOrDefault() |
Returns the first element if the query returns one or more results. Returns the default value if no results are returned. |
Last() |
Returns the last element if the query returns one or more results. Throws an exception if no results are returned. |
LastOrDefault() |
Returns the last element if the query returns one or more results. Returns the default value if no results are returned. |
Single() |
Returns the one element that returned the request. Throws an exception if none or more results are returned. |
SingleOrDefault() |
Returns the one element that returned the request. Returns the default value if no results are returned. Throws an exception if several results are returned. |
Extending LINQ
Definition of own monads
LINQ can be applied to any monad . Monads are adapters ( wrappers ) for a certain type. Predefined monads are e.g. B . ,, and .
IEnumerable<T>
IList<T>
Nullable<T>
Task<T>
However, own monads such as B. or can be created to extend the functionality of LINQ. Suitable extension methods must be defined for this. The use of monads serves to reduce the amount of boilerplate code.
IRepository<T>
IHandler<T>
identity
The simplest monad is the identity, which in .NET is commonly referred to as :
Identity<T>
public class Identity<T>
{
public T Value { get; private set; }
public Identity(T value)
{
Value = value;
}
}
The following extension methods can now be created for this class:
// Unit-Methode
// Konvertiert einen beliebigen Wert in eine Identität
public static Identity<T> ToIdentity<T>(this T value)
{
return new Identity<T>(value);
}
// Bind-Methode
// Verknüpft Funktionen die eine Identität zurückgeben
public static Identity<B> Bind<A, B>(this Identity<A> m, Func<A, Identity<B>> f)
{
return f(m.Value);
}
This monad can now be used as a lambda expression (as an arbitrary composition ):
var hello = "Hello".ToIdentity().Bind(h => "Monad".ToIdentity().Bind( m => String.Format("{0} {1}!", h, m) ));
Console.WriteLine(hello.Value); // "Hello Monad!"
In order to use the monad in LINQ, an extension method must be implemented. This is just an alias for . There is therefore the possibility
SelectMany()
Bind()
- Rename or encapsulate the method
Bind()
- to create and rename or encapsulate the method with function composition
Bind()
- both:
// SelectMany = Bind
public static Identity<B> SelectMany<A, B>(this Identity<A> m, Func<A, Identity<B>> f)
{
return Bind(m, f);
// alternativ mit aufgelöstem Bind():
// return f(m.Value);
}
// Bind mit Funktionskomposition
public static Identity<C> SelectMany<A, B, C>(this Identity<A> m, Func<A, Identity<B>> f, Func<A, B, C> select)
{
return select(m.Value, m.Bind(f).Value).ToIdentity();
// alternativ mit aufgelöstem Bind():
// return select(m.Value, f(m.Value).Value).ToIdentity();
}
The monad can now be processed using LINQ keywords:
var hello = from h in "Hello".ToIdentity()
from m in "Monad".ToIdentity()
select String.Format("{0} {1}!", h, m);
Console.WriteLine(hello.Value); // "Hello Monad!"
Maybe
Another simple monad is , which works similarly to the structure. The Maybe Monad can be implemented in different ways:
Maybe<T>
Nullable<T>
- version 1
- HasValue property determines whether Maybe Nothing (that is, empty).
Definition of the monad:
class Maybe<T>
{
public readonly static Maybe<T> Nothing = new Maybe<T>();
public T Value { get; private set; }
public bool HasValue { get; private set; }
Maybe()
{
HasValue = false;
}
public Maybe(T value)
{
Value = value;
HasValue = true;
}
public override string ToString()
{
return (HasValue) ? Value.ToString() : String.Empty;
}
}
Definition of the unit method:
public static Maybe<T> ToMaybe<T>(this T value)
{
return new Maybe<T>(value);
}
Definition of the bind method:
private static Maybe<U> Bind<T, U>(this Maybe<T> m, Func<T, Maybe<U>> f)
{
return (m.HasValue) ? f(m.Value) : Maybe<U>.Nothing;
}
public static Maybe<U> SelectMany<T, U>(this Maybe<T> m, Func<T, Maybe<U>> f)
{
return Bind<T, U>(m, f);
}
public static Maybe<C> SelectMany<A, B, C>(this Maybe<A> m, Func<A, Maybe<B>> f, Func<A, B, C> select)
{
return m.Bind(x => f(x).Bind(y => select(x,y).ToMaybe()));
}
Use:
// null-propagation of nullables
var r = from x in 5.ToMaybe()
from y in Maybe<int>.Nothing
select x + y;
Console.WriteLine(r.Value); // String.Empty
- Variant 2
- concrete type determines whether Nothing or Something
Definition of the monad:
public interface Maybe<T>{}
public class Nothing<T> : Maybe<T>
{
public override string ToString()
{
return String.Empty;
}
}
public class Something<T> : Maybe<T>
{
public T Value { get; private set; }
public Something(T value)
{
Value = value;
}
public override string ToString()
{
return Value.ToString();
}
}
Definition of the unit method:
public static Maybe<T> ToMaybe<T>(this T value)
{
return new Something<T>(value);
}
Definition of the bind method:
private static Maybe<B> Bind<A, B>(this Maybe<A> m, Func<A, Maybe<B>> f)
{
var some = m as Something<A>;
return (some == null) ? new Nothing<B>() : f(some.Value);
}
public static Maybe<B> SelectMany<A, B>(this Maybe<A> m, Func<A, Maybe<B>> f)
{
return Bind<A, B>(m, f);
}
public static Maybe<C> SelectMany<A, B, C>(this Maybe<A> m, Func<A, Maybe<B>> f, Func<A, B, C> select)
{
return m.Bind(x => f(x).Bind(y => select(x,y).ToMaybe()));
}
Use:
var r = from x in 5.ToMaybe() // Something<int>
from y in new Nothing<int>()
select x + y;
Console.WriteLine(r); // String.Empty
Define your own operators
Operators in LINQ can be extended by providing a suitable extension method. Standard operators can also be overwritten.
- example 1
- Return of people whose birthday is on a specific date.
public static class PersonExtensions
{
public static IEnumerable<TPerson> FilterByBirthday<TPerson>(this IEnumerable<TPerson> persons) where TPerson : Person
{
return FilterByBirthday(persons, DateTime.Now);
}
public static IEnumerable<TPerson> FilterByBirthday<TPerson>(this IEnumerable<TPerson> persons, DateTime date) where TPerson : Person
{
var birthdayPersons = select p in persons
where p.Birthday.Day == date.Day
where p.Birthday.Month == date.Month
select p;
// return the list of persons
foreach(Person p in birthdayPersons)
yield return p;
}
}
- Call the new extension method
personsToCongratulate = persons.FilterByBirthday();
- Example 2
- Definition of a method which returns the set of the oldest persons in a list. It should also be possible to specify a delegate function in order to filter out deceased people.
public static class PersonExtensions
{
public static IEnumerable<TPerson> Oldest<TPerson>(this IEnumerable<TPerson> source, Func<TPerson, Boolean> predicate) where TPerson : Person
{
// filter Persons for criteria
var persons = from p in source
where predicate(p)
select p;
// determine the age of the oldest persons
int oldestAge = (from p in persons
orderby p.Age descending
select p.Age).First();
// get the list of the oldest persons
var oldestPersons = select p in persons
where p.Age == youngestAge
select p;
// return the list of oldest persons
foreach (Person p in oldestPersons)
yield return p;
}
public static IEnumerable<TPerson> Oldest(this IEnumerable<TPerson> source) where TPerson : Person
{
return Oldest(source, x => true);
}
}
- Call the new extension method
oldestLivingPersons = persons.Oldest(p => p.Living == true);
Implementation of own LINQ providers
Writing your own LINQ provider is useful if a service is to be called that requires a certain syntax ( SQL , XML etc.). To make this possible, the IQueryable
interface must be implemented. The LINQ expression tree can be analyzed via this interface and converted into the appropriate target format.
Reactive extensions
The Reactive Extensions (short: Rx ) are an extension of LINQ, which works on instead of . It is an implementation of the observer design pattern .
IObservable<T>
IEnumerable<T>
Type of operation according to the CQS principle | Command | Query |
---|---|---|
definition | has side effects | returns data |
template | Observer | Iterator |
Implementation in the .NET Framework | Rx (IObservable) | LINQ (IEnumerable) |
template | Pipes and Filters | Map / Reduce |
Asynchronicity | All commands can be implemented asynchronously. |
Results are obtained with the help of
returned. |
The Rx enable event-driven programming without callback functions . Occasionally the Rx are described as "LINQ to Events".
Examples
LINQ to DataSet
The following example shows the query of a table with Linq. An existing Access database is required under the path: C: \ database.mdb with a Products table containing the ID , Name and EanCode fields .
The table is modeled as a class and provided with metadata using attributes that describe the mapping to the database.
To do this, a reference to the System.Data.Linq.Dll must be added in the project folder under References .
using System.Data.Linq.Mapping;
[Table(Name = "Products")]
class Product
{
[Column(Name = "id", IsPrimaryKey = true)]
public int ID;
[Column(Name = "Name")]
public string Name;
[Column(Name = "Ean")]
public string EanCode;
}
You can now query the table. The following example lists all products whose product name begins with an A. The products are sorted according to their ID.
using System.Configuration; // for ConfigurationManager
using System.Data; // for all interface types
using System.Data.Common; // for DbProviderFactories
class Foo()
{
public static void Main() {
// get connection settings from app.config
var cs = ConfigurationManager.ConnectionStrings["MyConnectionString"];
var factory = DbProviderFactories.GetFactory(cs.ProviderName);
using(IDbConnection connection = new factory.CreateConnection(cs.ConnectionString))
{
connection.Open();
DataContext db = new DataContext(connection);
Table<Product> table = db.GetTable<Product>();
var query = from p in table
where p.Name.StartsWith("A")
orderby p.ID
select p;
foreach (var p in query)
Console.WriteLine(p.Name);
}
}
}
Alternatively, so-called extension methods with lambda expressions can also be used. LINQ queries are also translated into these by the compiler.
var query = products
.Where(p => p.Name.StartsWith("A"))
.OrderBy(p => p.ID);
foreach (var product in query) {
Console.WriteLine(product.Name);
}
A single data record can be determined with the Single function . The following example determines the data record with ID 1.
Console.WriteLine(products.Single(p => p.ID == 1).Name);
However, if the query determines several data records, an InvalidOperationException is thrown.
LINQ to XML
Below is an example that shows how LINQ can be used to read information from an XML file. The following XML sample file is used as the XML file.
<?xml version="1.0"?>
<!-- purchase_order.xml -->
<PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20">
<Address Type="Shipping">
<Name>Ellen Adams</Name>
<Street>123 Maple Street</Street>
<City>Mill Valley</City>
<State>CA</State>
<Zip>10999</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
<Items>
<Item PartNumber="872-AA">
<ProductName>Lawnmower</ProductName>
<Quantity>1</Quantity>
<USPrice>148.95</USPrice>
<Comment>Confirm this is electric</Comment>
</Item>
<Item PartNumber="926-AA">
<ProductName>Baby Monitor</ProductName>
<Quantity>2</Quantity>
<USPrice>39.98</USPrice>
<ShipDate>1999-05-21</ShipDate>
</Item>
</Items>
</PurchaseOrder>
For example, if you wanted to read the part numbers ( PartNumber ) of all entries of the <Item> type, you could use the following C # code.
XElement purchaseOrder = XElement.Load("purchase_order.xml");
IEnumerable<string> items =
from item in purchaseOrder.Descendants("Item")
select (string)item.Attribute("PartNumber");
foreach (var item in items)
{
Console.WriteLine(partNumbers.ElementAt(i));
}
// Output:
// 872-AA
// 926-AA
Another option, using a conditional query, would be to select all items that are worth more than $ 100. In addition, the result of the query could be sorted according to the article numbers using orderby .
XElement purchaseOrder = XElement.Load("purchase_order.xml");
IEnumerable<XElement> items =
from item in purchaseOrder.Descendants("Item")
where (int)item.Element("Quantity") * (decimal)item.Element("USPrice") > 100
orderby (string)item.Element("PartNumber")
select item;
foreach(var item in items)
{
Console.WriteLine(item.Attribute("PartNumber").Value);
}
// Output:
// 872-AA
LINQ with Rx
Many of LINQ's extension methods are also present in Rx. In the following example, filtering is performed using the Where () clause:
using System;
using System.Reactive.Subjects;
using System.Reactive.Linq;
class Program
{
// Helper functions
private static Func<int,bool> isEven = n => n%2 == 0;
private static Func<int,bool> isOdd = n => !isEven(n);
private static Func<int,bool> isDivisibleBy5 = n => n%5 == 0;
static void Main()
{
var subject = new Subject<int>();
using(subject.Where(isEven).Where(isDivisibleBy5).Subscribe(_ => Console.WriteLine("FizzBuzz")))
using(subject.Where(isEven).Where(!isDivisibleBy5).Subscribe(_ => Console.WriteLine("Fizz")))
using(subject.Where(isOdd).Where(isDivisibleBy5).Subscribe(_ => Console.WriteLine("Buzz")))
using(subject.Where(isOdd).Where(!isDivisibleBy5).Subscribe(Console.WriteLine))
{
Observable.Range(1, 100).Subscribe(subject.OnNext);
}
}
}
The extension methods of Rx are defined ( IObservable<T>
instead of IEnumerable<T>
) for a different monad, but since the names of the extension methods are identical, the comprehension syntax of LINQ can also be used. Another possibility is therefore:
using System;
using System.Text;
using System.Reactive.Linq;
class Program
{
static string IntToFizzBuzz(int n)
{
return new StringBuilder(8)
.Append((n % 2 == 0) ? "Fizz" : string.Empty)
.Append((n % 5 == 0)? "Buzz" : string.Empty)
.Append((n % 2 != 0 && n % 5 != 0)? n.ToString() : string.Empty)
.ToString();
}
static void Main(string[] args)
{
var numbers = Observable.Range(1, 100);
var fizzBuzz = from n in numbers select IntToFizzBuzz(n);
fizzBuzz.Subscribe(Console.WriteLine);
}
}
literature
- Özgür Aytekin: LINQ - theory and practice for beginners . Addison-Wesley, Munich 2008, ISBN 978-3-8273-2616-4 .
- Andreas Kühnel: Visual C # 2010 . Galileo Press, Bonn 2010, ISBN 978-3-8362-1552-7 , LINQ to Objects, p. 465-496 .
- Paolo Pialorsi, Marco Russo: Database programming with Microsoft LINQ . Microsoft Press Germany, Unterschleißheim 2008, ISBN 978-3-86645-428-6 .
- Paolo Pialorsi, Marco Russo: Programming Microsoft LINQ in Microsoft .NET Framework 4 . Microsoft Press, Sebastopol CA 2010, ISBN 978-0-7356-4057-3 .
- Paolo Pialorsi: Microsoft SharePoint 2010 developer book . Microsoft Press Germany, Unterschleißheim 2011, ISBN 978-3-86645-545-0 , LINQ to SharePoint, p. 113-188 .
- Jesse Liberty, Paul Betts: Programming Reactive Extensions and LINQ . Apress, 2011, ISBN 978-1-4302-3747-1 , pp. 184 .
Web links
- LINQ (Language-Integrated Query). In: MSDN . Microsoft , accessed March 25, 2013 (LINQ homepage).
- LINQPad. Retrieved on March 25, 2013 (comfortable editor for creating and executing LINQ scripts).
- Don Box, Anders Hejlsberg : The LINQ Project. Microsoft , September 2005, accessed March 16, 2013 ( Microsoft information page ).
- Roger Jennings: Third-Party LINQ Providers. OakLeaf Systems, March 27, 2007, accessed March 16, 2013 (List of various LINQ providers outside of Microsoft).
- Jan Welker: LINQ to XML Part 1 - Creating an XML file. June 19, 2008, accessed March 16, 2013 (Introduction to LINQ to XML; three-part series of articles).
- Jan Welker: LINQ to XML Part 2 - Querying an XML file. June 21, 2008, Retrieved March 16, 2013 (Introduction to LINQ to XML; three-part series of articles).
- Jan Welker: LINQ to XML Part 3 - Manipulating an XML file. June 22, 2008, Retrieved March 16, 2013 (Introduction to LINQ to XML; three-part series of articles).
- Robert Mühsig: HowTo: O / R Mapper LINQ to SQL - Introduction & simple manual mapping. Code Inside Blog, January 15, 2008, accessed on March 16, 2013 (German-language introduction to LINQ to SQL).
- James Hare: Demystifying LINQ. Tech.Pro, March 14, 2013, accessed March 16, 2013 .
- Richard Carr: LINQ Style Variance and Standard Deviation Operators. BlackWasp, April 2, 2013, accessed April 3, 2013 (English, extension methods for calculating standard deviation and variance with LINQ).
LINQ in other programming languages
- Query Expressions (F #). In: MSDN. Microsoft, accessed on May 18, 2014 (English, LINQ variant in F #).
- Breeze.js. Retrieved May 18, 2014 (English, LINQ style queries for HTML5 Web Storage).
- linq.js. In: CodePlex. Retrieved April 3, 2013 (LINQ for JavaScript).
- JSINQ. In: CodePlex. Retrieved April 3, 2013 (LINQ to Objects for JavaScript).
- Java Streams API
- Quaere. Codehaus Foundation, accessed April 3, 2013 .
- JaQue - JAva integrated QUEry library. In: Google Code. Retrieved April 3, 2013 (English, LINQ to Objects; compatible with Java 7 closures).
- jOOQ - Java Object Oriented Querying. Retrieved April 3, 2013 (LINQ to SQL).
- Query DSL. Retrieved April 3, 2013 (English, supports JPA , JDO, and SQL ).
- Jinq
- phinq. In: Google Code. Retrieved April 3, 2013 (English, LINQ for PHP).
- PHPLinq. In: CodePlex. Retrieved April 3, 2013 (English, LINQ for PHP).
- asq. In: Google Code. Retrieved April 3, 2013 (English, Python implementation for LINQ to Objects and Parallel LINQ to Objects ).
Individual evidence
- ↑ Erik Meijer. Microsoft Research , accessed March 16, 2013 .
- ↑ a b Paolo Pialorsi: Developer book Microsoft SharePoint 2010 . Microsoft Press Germany, Unterschleißheim 2011, ISBN 978-3-86645-545-0 , LINQ to SharePoint, p. 115 .
- ↑ Paolo Pialorsi, Marco Russo: Programming Microsoft LINQ in Microsoft .NET Framework 4 . Microsoft Press, Sebastopol California 2010, ISBN 978-0-7356-4057-3 , pp. 5 .
- ↑ Paolo Pialorsi, Marco Russo: Programming Microsoft LINQ in Microsoft .NET Framework 4 . Microsoft Press, Sebastopol California 2010, ISBN 978-0-7356-4057-3 , pp. 8-17 .
- ↑ Paolo Pialorsi: Developer book Microsoft SharePoint 2010 . Microsoft Press Germany, Unterschleißheim 2011, ISBN 978-3-86645-545-0 , LINQ to SharePoint, p. 115 (based on).
- ^ Brian Beckman: Don't fear the Monad. In: Channel9 . Microsoft , accessed March 20, 2013 .
- ↑ The Marvels of Monads. In: MSDN Blog. Microsoft , January 10, 2008, accessed March 20, 2013 .
- ↑ LINQ Query Expressions (C # Programming Guide). In: MSDN. Microsoft, accessed March 21, 2013 .
- ↑ Query Expressions (F #). In: MSDN. Microsoft, accessed March 21, 2013 .
- ↑ Paolo Pialorsi, Marco Russo: Programming Microsoft LINQ in Microsoft .NET Framework 4 . Microsoft Press, Sebastopol California 2010, ISBN 978-0-7356-4057-3 , pp. 6-8 .
- ↑ Paolo Pialorsi, Marco Russo: Programming Microsoft LINQ in Microsoft .NET Framework 4 . Microsoft Press, Sebastopol California 2010, ISBN 978-0-7356-4057-3 , pp. 7 .
- ↑ Paolo Pialorsi: Developer book Microsoft SharePoint 2010 . Microsoft Press Germany, Unterschleißheim 2011, ISBN 978-3-86645-545-0 , LINQ to SharePoint, p. 114 .
- ↑ Paolo Pialorsi, Marco Russo: Programming Microsoft LINQ in Microsoft .NET Framework 4 . Microsoft Press, Sebastopol California 2010, ISBN 978-0-7356-4057-3 , pp. 241 ff .
- ↑ Paolo Pialorsi: Developer book Microsoft SharePoint 2010 . Microsoft Press Germany, Unterschleißheim 2011, ISBN 978-3-86645-545-0 , LINQ to SharePoint, p. 188 ff .
- ↑ Enumerable.SelectMany method. In: MSDN. Microsoft, accessed March 21, 2013 .
- ↑ Types That Allow NULL Values (C # Programming Guide). In: MSDN. Microsoft, accessed March 21, 2013 .
- ↑ Nullable <T> structure. In: MSDN. Microsoft, accessed March 21, 2013 .
- ↑ XML example file : Typical order (LINQ to XML). MSDN , accessed March 16, 2013 .
- ↑ Overview of LINQ to XML. MSDN , accessed March 16, 2013 .
- ↑ Java Streams Preview vs .Net High-Order Programming with LINQ. (No longer available online.) Informatech Costa Rica, archived from the original on April 1, 2013 ; accessed on April 3, 2013 . Info: The archive link was inserted automatically and has not yet been checked. Please check the original and archive link according to the instructions and then remove this notice.
- ↑ Jinq. In: website of jing.org. Retrieved August 15, 2019 .