LINQ (Language Integrated Query)

What is it?

LINQ provides language-level querying capabilities and a higher-order function API to C# and VB as a way to write expressive, declarative code.

Language-level query syntax:

C#

var linqExperts = from p in programmers
                  where p.IsNewToLINQ
                  select new LINQExpert(p);

Same example using the IEnumerable<T> API:

C#

var linqExperts = programmers.Where(p => IsNewToLINQ)
                             .Select(p => new LINQExpert(p));

LINQ is Expressive

Imagine you have a list of pets, but want to convert it into a dictionary where you can access a pet directly by its RFID value.

Traditional imperative code:

C#

var petLookup = new Dictionary<int, Pet>();

foreach (var pet in pets)
{
    petLookup.Add(pet.RFID, pet);
}

The intention behind the code is not to create a new Dictionary<int, Pet> and add to it via a loop, it is to convert an existing list into a dictionary! LINQ preserves the intention whereas the imperative code does not.

Equivalent LINQ expression:

C#

var petLookup = pets.ToDictionary(pet => pet.RFID);

The code using LINQ is valuable because it evens the playing field between intent and code when reasoning as a programmer. Another bonus is code brevity. Imagine reducing large portions of a codebase by 1/3 as done above. Pretty sweet deal, right?

LINQ Providers Simplify Data Access

For a significant chunk of software out in the wild, everything revolves around dealing with data from some source (Databases, JSON, XML, etc). Often this involves learning a new API for each data source, which can be annoying. LINQ simplifies this by abstracting common elements of data access into a query syntax which looks the same no matter which data source you pick.

Consider the following: finding all XML elements with a specific attribute value.

C#

public static IEnumerable<XElement> FindAllElementsWithAttribute(XElement documentRoot, string elementName,
                                           string attributeName, string value)
{
    return from el in documentRoot.Elements(elementName)
           where (string)el.Element(attributeName) == value
           select el;
}

Writing code to manually traverse the XML document to perform this task would be far more challenging.

Interacting with XML isn’t the only thing you can do with LINQ Providers. Linq to SQL is a fairly bare-bones Object-Relational Mapper (ORM) for an MSSQL Server Database. The JSON.NET library provides efficient JSON Document traversal via LINQ. Furthermore, if there isn’t a library which does what you need, you can also write your own LINQ Provider!

Why Use the Query Syntax?

This is a question which often comes up. After all, this,

C#

var filteredItems = myItems.Where(item => item.Foo);

is a lot more concise than this:

C#

var filteredItems = from item in myItems
                    where item.Foo
                    select item;

Isn’t the API syntax just a more concise way to do the query syntax?

No. The query syntax allows for the use the let clause, which allows you to introduce and bind a variable within the scope of the expression, using it in subsequent pieces of the expression. Reproducing the same code with only the API syntax can be done, but will most likely lead to code which is hard to read.

So this begs the question, should you just use the query syntax?

The answer to this question is yes if...

  • Your existing codebase already uses the query syntax
  • You need to scope variables within your queries due to complexity
  • You prefer the query syntax and it won’t distract from your codebase

The answer to this question is no if...

  • Your existing codebase already uses the API syntax
  • You have no need to scope variables within your queries
  • You prefer the API syntax and it won’t distract from your codebase

Essential Samples

For a truly comprehensive list of LINQ samples, visit 101 LINQ Samples.

The following is a quick demonstration of some of the essential pieces of LINQ. This is in no way comprehensive, as LINQ provides significantly more functionality than what is showcased here.

  • The bread and butter - WhereSelect, and Aggregate:

C#

// Filtering a list
var germanShepards = dogs.Where(dog => dog.Breed == DogBreed.GermanShepard);

// Using the query syntax
var queryGermanShepards = from dog in dogs
                          where dog.Breed == DogBreed.GermanShepard
                          select dog;

// Mapping a list from type A to type B
var cats = dogs.Select(dog => dog.TurnIntoACat());

// Using the query syntax
var queryCats = from dog in dogs
                select dog.TurnIntoACat();

// Summing then lengths of a set of strings
int seed = 0;
int sumOfStrings = strings.Aggregate(seed, (s1, s2) => s1.Length + s2.Length);
  • Flattening a list of lists:

C#

// Transforms the list of kennels into a list of all their dogs.
var allDogsFromKennels = kennels.SelectMany(kennel => kennel.Dogs);
    • Union between two sets (with custom comparator):

1

C#

public class DogHairLengthComparer : IEqualityComparer<Dog>
{
    public bool Equals(Dog a, Dog b)
    {
        if (a == null && b == null)
        {
            return true;
        }
        else if ((a == null && b != null) ||
                 (a != null && b == null))
        {
            return false;
        }
        else
        {
            return a.HairLengthType == b.HairLengthType;
        }
    }

    public int GetHashCode(Dog d)
    {
        // default hashcode is enough here, as these are simple objects.
        return b.GetHashCode();
    }
}

...

// Gets all the short-haired dogs between two different kennels
var allShortHairedDogs = kennel1.Dogs.Union(kennel2.Dogs, new DogHairLengthComparer());
  • Intersection between two sets:

C#

// Gets the volunteers who spend share time with two humane societies.
var volunteers = humaneSociety1.Volunteers.Intersect(humaneSociety2.Volunteers,
                                                     new VolunteerTimeComparer());
  • Ordering:

C#

// Get driving directions, ordering by if it‘s toll-free before estimated driving time.
var results = DirectionsProcessor.GetDirections(start, end)
              .OrderBy(direction => direction.HasNoTolls)
              .ThenBy(direction => direction.EstimatedTime);
  • Finally, a more advanced sample: determining if the values of the properties of two instances of the same type are equal (Borrowed and modified from this StackOverflow post):

C#

public static bool PublicInstancePropertiesEqual<T>(this T self, T to, params string[] ignore) where T : class
{
    if (self != null && to != null)
    {
        var type = typeof(T);
        var ignoreList = new List<string>(ignore);

        // Selects the properties which have unequal values into a sequence of those properties.
        var unequalProperties = from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                where !ignoreList.Contains(pi.Name)
                                let selfValue = type.GetProperty(pi.Name).GetValue(self, null)
                                let toValue = type.GetProperty(pi.Name).GetValue(to, null)
                                where selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))
                                select new { Prop = pi.Name, selfValue, toValue };
        return !unequalProperties.Any();
    }

    return self == to;
}

PLINQ

PLINQ, or Parallel LINQ, is a parallel execution engine for LINQ expressions. In other words, a regular LINQ expressions can be trivially parallelized across any number of threads. This is accomplished via a call to AsParallel() preceding the expression.

Consider the following:1

C#

public static string GetAllFacebookUserLikesMessage(IEnumerable<FacebookUser> facebookUsers)
{
    var seed = default(UInt64);

    Func<UInt64, UInt64, UInt64> threadAccumulator = (t1, t2) => t1 + t2;
    Func<UInt64, UInt64, UInt64> threadResultAccumulator = (t1, t2) => t1 + t2;
    Func<Uint64, string> resultSelector = total => $"Facebook has {total} likes!";

    return facebookUsers.AsParallel()
                        .Aggregate(seed, threadAccumulator, threadResultAccumulator, resultSelector);
}

This code will partition facebookUsers across system threads as necessary, sum up the total likes on each thread in parallel, sum the results computed by each thread, and project that result into a nice string.

In diagram form:

Parallelizable CPU-bound jobs which can be easily expressed via LINQ (in other words, are pure functions and have no side effects) are a great candidate for PLINQ. For jobs which do have a side effect, consider using the Task Parallel Library.

时间: 2024-10-10 23:44:01

LINQ (Language Integrated Query)的相关文章

Liam的C# 学习历程(六):LINQ(Language-INtegrated Query)

在这一周的C#课程中,我们学习了一些在C#编程中需要用到的对数据库或XML文件进行处理的操作,这就是LINQ,它使得一种类似与我们在数据库中常用的SQL语言的查询语言成为了C#语言的一部分,方便了我们搜索数据库等方面的操作.下面我们就来一起复习一下. (一)创建LINQ(Creating the Query): 1.From字句(The from clause):指定范围变量和数据源 from customer in customers //customer:range variable fro

PL/SQL(Procedure Language &amp; Structured Query Language)

目前的PL/SQL包括两部分,一部分是数据库引擎部分:另一部分是可嵌入到许多产品(如C语言,JAVA语言等)工具中的独立引擎.可以将这两部分称为:数据库PL/SQL和工具PL/SQL. PL/SQL中的基本单位是块(Block),所有PL/SQL程序都是由块组成的.PL/SQL中的块由3部分组成:声明部分,程序代码.异常处理代码.如下: DECLARE  /* 声明部分: 在此声明PL/SQL用到的变量,类型及游标,以及局部的存储过程和函数 */ BEGIN /*  执行部分:  过程及SQL

PL/SQL : Procedural Language / Structual Query Language and it is an exrension to SQL.

SQL is not very flexible and it cannot be made to react differently to differing sutuations easily. In  SQL queries we normally tell database what we want but not tell it how to do it. SQL : give commands, commands complete with ; PL/SQL : follow the

Linq入门——什么是linq &amp; 扩展方法

一,什么是Linq linq(language integrated Query):语言集成查询: linq包含如下: 对对象的查询,对数据库的查询,对XML的查询. 那么,没有linq前我们是怎样查询的? 先看一个例子: 现在我们要查询大于50的数,: 在没有linq之前,我们的代码时这样的: 使用了linq查询: 首先,从直观上看,代码更加简洁,其次,对于查询部分,接近SQL语句,层次清晰,容易理解: 除了简单高效以为,LINQ的出现解决了很多问题: 1,面向对象与数据访问两个领域长期分裂,

C#参考:Linq 概述

Linq (Language Integrated Query,语言集成查询),是微软公司提供的一项新技术,它能够将查询功能引入到.NET 3.5 所支持的编程语言中,例如C#,Visual Basic.NET.查询操作通过编程语言自身来表达,而不再是以字符串的形式嵌入到应用程序中. Linq主要包含下面四个组件: Linq to Objets.Linq to Sql.Linq to DataSet和Linq to XML,它们分别用于查询和处理对象数据(如集合等).关系数据.DataSet对象

LINQ基础(一)

LINQ(Language Integrated Query,语言集成查询),在C#语言中集成了查询语法,可以用相同的语法访问不同的数据源. LINQ提供了不同数据源的抽象层,所以可以使用相同的语法. 这里主要介绍LINQ的核心原理和C#中支持C# LINQ查询的语言扩展. 1.语法 使用LINQ查询出来自巴西的所以世界冠军.这里可以使用List<T>类的FindAll()方法,但使用LINQ查询语法更简单 static void LINQQuery() { // var query = fr

LINQ实战

转载:http://www.cnblogs.com/yubinfeng/p/4567064.html    原作者:尼古拉斯~yu 文章部分内容在原文的基础上有删改. 我相信在net进阶的这个阶段,很多人对泛型,委托是很头疼的,有幸的是这次项目实战经历了这些,在此做个记录.(ps:转载的文章我的同事,可以称作大牛的尼古拉斯~yu) LINQ: Language Integrated Query(语言集成查询)的简称,它是集成在.NET编程语言中的一种特性. 1.LINQ的构架 从这幅图中,我们可

LinQ学习手册

LinQ : Language Integrated Query(语言集成查询); 1.以统一方式操作各种数据源,减少数据访问的复杂性. 优点在于封装了SQL语句,只对对象进行操作(增删改查),代码量大大减少,同时把我们引入面向对象编程方式上来, 其本质是对ADO.NET结果集通过反射连同泛型特性转换成对象集,实现OR模型的转换, 缺点:性能上比ADO.NET差,需要OR转换,对一些复杂的sql语句不好操作(linq好像支持sql)?. 2.linq to sql a.linq to sql 是

译:在C#中使用LINQ To SQL

译文出处:http://www.codeproject.com/Tips/871938/LINQ-To-SQL-Using-Csharp 今天在这个话题中,我给大家分享一个在c#编程中非常有趣和十分有用的特性. 开始之前,我想告诉大家关于Linq的基本信息.比如:什么是linq?然后再来分享实际应用. 说明: LINQ = Language Integrated Query(集成查询语言) Linq是微软在.NET Framework 3.5中信增加的一个特性.它是用来查询数据库和对数据库查询的