LINQ

from Wikipedia, the free encyclopedia

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

Major LINQ providers

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()TSourceGetHashCode()

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:

scalar LINQ selectors
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()

  1. Rename or encapsulate the methodBind()
  2. to create and rename or encapsulate the method with function compositionBind()
  3. 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 IQueryableinterface 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>

Comparison of Rx with LINQ
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

  • asynchronous notifications or
  • Status polling tokens

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 in other programming languages

F #

JavaScript , TypeScript
  • 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

PHP

  • phinq. In: Google Code. Retrieved April 3, 2013 (English, LINQ for PHP).
  • PHPLinq. In: CodePlex. Retrieved April 3, 2013 (English, LINQ for PHP).

python

  • asq. In: Google Code. Retrieved April 3, 2013 (English, Python implementation for LINQ to Objects and Parallel LINQ to Objects ).

Individual evidence

  1. Erik Meijer. Microsoft Research , accessed March 16, 2013 .
  2. 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 .
  3. 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 .
  4. 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 .
  5. 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).
  6. ^ Brian Beckman: Don't fear the Monad. In: Channel9 . Microsoft , accessed March 20, 2013 .
  7. The Marvels of Monads. In: MSDN Blog. Microsoft , January 10, 2008, accessed March 20, 2013 .
  8. LINQ Query Expressions (C # Programming Guide). In: MSDN. Microsoft, accessed March 21, 2013 .
  9. Query Expressions (F #). In: MSDN. Microsoft, accessed March 21, 2013 .
  10. 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 .
  11. 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 .
  12. Paolo Pialorsi: Developer book Microsoft SharePoint 2010 . Microsoft Press Germany, Unterschleißheim 2011, ISBN 978-3-86645-545-0 , LINQ to SharePoint, p. 114 .
  13. 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 .
  14. 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 .
  15. Enumerable.SelectMany method. In: MSDN. Microsoft, accessed March 21, 2013 .
  16. Types That Allow NULL Values ​​(C # Programming Guide). In: MSDN. Microsoft, accessed March 21, 2013 .
  17. Nullable <T> structure. In: MSDN. Microsoft, accessed March 21, 2013 .
  18. XML example file : Typical order (LINQ to XML). MSDN , accessed March 16, 2013 .
  19. Overview of LINQ to XML. MSDN , accessed March 16, 2013 .
  20. 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.  @1@ 2Template: Webachiv / IABot / blog.informatech.cr
  21. Jinq. In: website of jing.org. Retrieved August 15, 2019 .