详解LINQ入门(下篇)

前 言

终于来到下篇了,通过上篇,和中篇,我们了解了linq的基本语句,对应linq我们又了解到lambda表达式,静态扩展方法,以及linq的延迟加载的特性,那么在本篇文章中我们将分享学习一下linq对于我们开发中常用到的对象的操作应用。如果没有阅读过上篇的请点击这里,如果没有阅读中篇的请点击这里

linq to DataSet

对于做.net 开发的有谁不知道DataSet,DataTable,DataRow,DataColumn这些对象,如果你真的不知道,那好吧建议你到菜市场买2块豆腐撞死算了>_<。也许你会惊讶,哇靠!linq能操作这些?答案是肯定的。那么我们来看看linq是怎么操作的。

1. 命名空间,如果需要linq操作DataSet,需要以下命名空间

using System.Data;
using System.Linq;

2. 关键方法 AsEnumerable,该方法为一个静态扩展方法,他将DataTable转换为一个IEnumerable<DataRow>的序列

var dt = new DataTable();
dt.Columns.Add("A", typeof(int));

var newRow1 = dt.NewRow();
var newRow2 = dt.NewRow();

newRow1["A"] = 1;
newRow2["A"] = 2;

dt.Rows.Add(newRow1);
dt.Rows.Add(newRow2);

// 重点看这里
IEnumerable<DataRow> rows = dt.AsEnumerbale();

foreach(row in rows)
  Console.WriteLine(row["A"].ToString());

从这段代码看,并没有什么实质意义,如果这样去遍历datarow就是脱裤子放屁,多此一举。但是这样做的目只有一个为下面的linq操作做铺垫。

3. linq 对 DataRow 操作,以下举例一些linq特有的常用datarow操作

Distinct,顾名思义该方法返回的没有重复值的datarow序列

var dt = new DataTable();
dt.Columns.Add("A", typeof(int));

var newRow1 = dt.NewRow();
var newRow2 = dt.NewRow();

newRow1["A"] = 1;
newRow2["A"] = 2;
newRow3["A"] = 2;

dt.Rows.Add(newRow1);
dt.Rows.Add(newRow2);
dt.Rows.Add(newRow3);

// 重点看这里
IEnumerable<DataRow> rows = dt.AsEnumerbale();
// 去重复
IEnumerable<DataRow> distinctRows = rows.Distinct(DataRowComparer.Default);

foreach(var row in distictRows)
  Console.WriteLine(row["A"].ToString());

// 结果
// 1
// 2

注意,这里的 DataRowComparer 是一个静态类,属性 Default 表示返回单一的DataRow实例

Except, 找到DataRow序列A中在datarow序列B中没有的datarow序列

var dt1 = new DataTable();
dt1.Columns.Add("A", typeof(int));

var dt2 = new DataTable();
dt2.Columns.Add("A", typeof(int));

dt1.Rows.Add(new object[] { 1 });
dt1.Rows.Add(new object[] { 2 });

dt2.Rows.Add(new object[] { 2 });
dt2.Rows.Add(new object[] { 3 });

// 重点看这里
IEnumerable<DataRow> rows1 = dt1.AsEnumerable();
IEnumerable<DataRow> rows2 = dt2.AsEnumerable();

// 获取rows1中在rows2里没有包含的datarow序列
var rows3 = rows1.Except(rows2, DataRowComparer.Default);

foreach (var row in rows3)
  Console.WriteLine(row["A"].ToString());

// 结果
// 1

Intersect, 两个DataRow序列的交集

var dt1 = new DataTable();
dt1.Columns.Add("A", typeof(int));

var dt2 = new DataTable();
dt2.Columns.Add("A", typeof(int));

dt1.Rows.Add(new object[]{1});
dt1.Rows.Add(new object[]{2});

dt2.Rows.Add(new object[]{2});
dt2.Rows.Add(new object[]{3});

// 重点看这里
IEnumerable<DataRow> rows1 = dt1.AsEnumerbale();
IEnumerable<DataRow> rows2 = dt2.AsEnumerbale();

// 获取rows1与rows2共有的datarow序列
rows1.Intersect(row2, DataRowComparer.Default); 

foreach(var row in rows1)
  Console.WriteLine(row["A"].ToString());
// 结果
// 2

Union,合并两个datarow序列

var dt1 = new DataTable();
dt1.Columns.Add("A", typeof(int));

var dt2 = new DataTable();
dt2.Columns.Add("A", typeof(int));

dt1.Rows.Add(new object[] { 1 });
dt1.Rows.Add(new object[] { 2 });

dt2.Rows.Add(new object[] { 2 });
dt2.Rows.Add(new object[] { 3 });

// 重点看这里
IEnumerable<DataRow> rows1 = dt1.AsEnumerable();
IEnumerable<DataRow> rows2 = dt2.AsEnumerable();

// 合并rows1与rows2
var row3 = rows1.Union(rows2, DataRowComparer.Default);

foreach (var row in row3)
  Console.WriteLine(row["A"].ToString());
// 结果
// 1
// 2
// 3

SequenceEqual,判断两个dataorw序列是否相等

var dt1 = new DataTable();
dt1.Columns.Add("A", typeof(int));

var dt2 = new DataTable();
dt2.Columns.Add("A", typeof(int));

dt1.Rows.Add(new object[]{1});
dt1.Rows.Add(new object[]{2});

dt2.Rows.Add(new object[]{2});
dt2.Rows.Add(new object[]{3});

// 重点看这里
IEnumerable<DataRow> rows1 = dt1.AsEnumerbale();
IEnumerable<DataRow> rows2 = dt2.AsEnumerbale();

// 合并rows1与rows2
var equal = rows1.SequenceEqual(row2, DataRowComparer.Default); 

Console.WriteLine(equal.ToString());

// 结果
// false

4. linq 对 DataColumn 操作

在了解了对datarow的操作后,我们再来了解一下对datacolumn的操作

Field<T> , 它是一个获取当前行(datarow)的某一列值的静态扩展方法,它具有三种重载参数,类型分别是DataColumn, String, Int,在这里建议大家使用string 类型参数,明确是取哪一列,语句阅读上更流畅。

var dt = new DataTable();
dt.Columns.Add("A", typeof(int));

var newRow1 = dt.NewRow();
var newRow2 = dt.NewRow();

newRow1["A"] = 1;
newRow2["A"] = 2;

dt.Rows.Add(newRow1);
dt.Rows.Add(newRow2);

IEnumerable<DataRow> rows = dt.AsEnumerbale();

// 重点看这里
foreach(var val in rows.Select(e => e.Field<int>("A"))
  Console.WriteLine(val.ToString());

SetField<T> , 该方法刚好是对当前行某一列进行赋值操作,同样也具有三种重载参数DataColumn, String, Int,在这里建议大家使用string 类型参数,明确是取哪一列,语句阅读上更流畅。

var dt = new DataTable();
dt.Columns.Add("A", typeof(int));

var newRow1 = dt.NewRow();
var newRow2 = dt.NewRow();

newRow1["A"] = 1;
newRow2["A"] = 2;

dt.Rows.Add(newRow1);
dt.Rows.Add(newRow2);

IEnumerable<DataRow> rows = dt.AsEnumerbale();

// 重点看这里
foreach(var row in rows)
  row.SetField<int>("A", row.Field<int>("A")+10);

foreach(var val in rows.Select(e => e.Field<int>("a")))
  Console.WriteLine(val.ToString())

// 结果
// 11
// 12

5. CopyToDataTable<DataRow>,该方法是将datarow序列组成一个新的DataTable

// 已知一个DataTable
var dt = new DataTable();

// 获取一个DataRow序列
var rows = dt.AsEnumerable();

//经过一系列操作
// ....

//获取一个新的DataTable
var newDt = rows.CopyToDataTable();

至此,我们对linq to DataSet 有了一个基本认识与了解,那么下面我们将了解另一个应用 linq to xml

 linq to XML

在实际应用中,并不需要我们使用linq对xml对象进行操作,因为MS已经提供了封装对xml的linq操作的对象,我们一起来简单的了解下有哪些对象。

1.命名空间,linq to xml 需要如下命名空间

using System.Linq;
using System.Xml.Linq;

2. linq to xml 主要类型对象

  • XDocument : 表示 XML 文档
  • XElement : 表示一个 XML 元素
  • XAttribute : 表示一个 XML 特性(节点属性)
  • XNamespace : 表示一个 XML 命名空间
  • XCData : 表示一个包含 CDATA 的文本节点(注释)
  • XDeclaration : 表示一个 XML 声明
 // 创建一个XML文档
var xDoc = new XDocument(
  // 定义声明
  new XDeclaration("1.0", "utf-8", "yes"),
    // 添加根节点
    new XElement("root",
      // 添加子节点1,并添加节点属性“name”
      new XElement("item1", new XAttribute("name","属性"), "子节点1"),
      // 添加子节点2,并添加内容注释CDATA
      new XElement("item2", new XCData("注释"))));

// 输出结果
//<?xml version="1.0" encoding="utf-8" standalone="yes"?>
//<root>
// <item1 name="属性">子节点1</item1>
// <item2><![CDATA[注释]]></item2>
//</root>

2. 输出XML文档,当我们创建好一个xml文档对象时,调用该对象的方法 Save 即可,如下:

// 创建一个XML文档
var xDoc = new XDocument(
  // 定义声明
  new XDeclaration("1.0", "utf-8", "yes"),
    // 添加根节点
    new XElement("root",
      // 添加子节点1,并添加节点属性“name”
      new XElement("item1", new XAttribute("name","属性"), "子节点1"),
      // 添加子节点2,并添加内容注释CDATA
      new XElement("item2", new XCData("注释"))));

// 输出XML文档
xDoc.Save("demo.xml");

3. 导入xml文档,如果已知一个XML文本文件,我们需要获取这个xml文本文件XDocment对象时,可以执行改对象方法 Load,该方法具有八种参数重载,参数类型分别是Stream,String,TextReader,XmlReader。下面的示例中使用的是 string 类型参数传递

XDocment xDoc = XDocument.Load("demo.xml");

4. XNode 抽象基类,表示 XML 树中节点的抽象概念(元素、注释、文档类型、处理指令或文本节点),简单理解就是我们可以把XML的内容每一个部分都视为节点,也就是说它是类型的基类,并提供了大量的操作xml方法。

摘自MSDN:

XNode 是以下类型的抽象公共基类:

  • XComment
  • XContainer
  • XDocumentType
  • XProcessingInstruction
  • XText

XContainer 是以下类型的抽象公共基类:

  • XDocument
  • XElement

派生自 XContainer 的类的对象可以包含子节点。

5. 常用遍历方法

  • DescendantNodes : 按文档顺序返回此文档或元素的子代节点集合。
  • Elements : 按文档顺序返回此元素或文档的子元素集合
var xDoc = XDocument.Load("demo.xml");

IEnumerable<XNode> nodex = xDoc.DescendantNodes();
IEnumerable<XElement> elems = xDoc.Elements();

当我们获取到到节点或者元素的序列后就可以对这些对象进行常规的LINQ操作,例如运用前两篇介绍的知识。

由于篇幅关系,这里就不逐一去讲解每个LINQ TO XML的API了,感兴趣的读者可以去msdn查阅System.Xml.Linq命名空间下的操作对象。

总 结

(吐槽)当我写完这篇文章时,自我感觉很枯燥,通篇介绍的都是API封装没有体现出LINQ的新意,想删掉这篇文章的冲动都有,但是一想既然我们要学习LINQ,这些东西还是需要适当了解与接触,所以还是硬着头皮写下来了,如果你能看完整篇文章,那真的非常感谢,感谢你的支持。

linq to xml 在效率上和 xml 的 xpath 差不了多少,所以在什么情况下怎么使用任君选择,并不需要强制使用的。

linq to dataset 小数据的时候可以这么干,但是数据量大时候,我建议不要这么干,首先要执行AsEnumberable这样一个耗时的方法划不来,不如直接上foreach遍历。

最终篇将和大家分享并讨论最受大家所熟知的LINQ TO SQL,还是希望大家给予一点期待吧。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解LINQ入门(中篇)

    前 言 在上篇中简单的分享了LINQ的基础概念及基础语法,如果没有阅读过上篇的朋友可以点击这里.感谢大家的支持,本篇我们将更进一步的学习LINQ的一些相关特性及应用方法.废话不多说,请往下阅读吧. 延迟加载 在上篇中简单的和大家提到了LINQ具有一个很有意思的特性那就是"延迟加载"(或"延迟计算"),什么是延迟加载呢?先看来自官方的描述:延迟执行意味着表达式的计算延迟,直到真正需要它的实现值为止.是不是觉得有点生涩难理解呢?按照我个人的理解通俗的讲就是,每当我们编写

  • 详解LINQ入门(上篇)

    前 言 最近和我们老大一起做技术面试(我是旁听的),发现前来面试的没几个掌握甚至是丁点了解LINQ.这让我很纳闷,LINQ伴随2008一起发布至今难道大家真的没时间去了解一下或者学习一下这个应用基础吗.甚至问及有些人LINQ是什么,答题者想都不想 LINQ TO SQL, 崩溃!没错,LINQ是可以TO SQL,但是除了SQL,LINQ就无所作为了?非也.因此在这里和大家一起分享学习LINQ.本文适合以下读者, 如果你是不符合者请赏脸捧个场,3Q 从未触碰过LINQ的 对LINQ有过了解但是从未

  • 详解LINQ入门(下篇)

    前 言 终于来到下篇了,通过上篇,和中篇,我们了解了linq的基本语句,对应linq我们又了解到lambda表达式,静态扩展方法,以及linq的延迟加载的特性,那么在本篇文章中我们将分享学习一下linq对于我们开发中常用到的对象的操作应用.如果没有阅读过上篇的请点击这里,如果没有阅读中篇的请点击这里 linq to DataSet 对于做.net 开发的有谁不知道DataSet,DataTable,DataRow,DataColumn这些对象,如果你真的不知道,那好吧建议你到菜市场买2块豆腐撞死

  • 详解webpack 入门与解析

    每次学新东西总感觉自己是不是变笨了,看了几个博客,试着试着就跑不下去,无奈只有去看官方文档. webpack是基于node的.先安装最新的node. 1.初始化 安装node后,新建一个目录,比如html5.cmd中切到当前文件夹. npm init -y 这个命令会创建一个默认的package.json.它包含了项目的一些配置参数,通过它可以进行初始安装.详细参数:https://docs.npmjs.com/files/package.json. 不要y参数的话,会在命令框中设置各项参数,但

  • 详解Unity入门之GameObject

    GameObject和Component GameObject是游戏场景中真实存在的,而且有位置的一个物件 Component附属于GameObject,控制GameObject的各种属性 GameObject是由Component组合成的,Component的生命周期和GameObject息息相关.调用此GameObject的Destroy方法,它的子对象和对应的所有Component都会被销毁,但也可以一次只销毁一个Component 常见的Component: Component 作用 R

  • 实例详解SpringMVC入门使用

    MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model),视图(View)和控制器(Controller).通过分层使开发的软件结构更清晰,从而达到开发效率的提高,可维护性和扩展性得到提高.Spring提供的MVC框架是在J2EE Web开发中对MVC模式的一个实现,本文通过实例讲解一下Spring MVC 的使用. 先来看一个HTTP request在Spring的MVC框架是怎么被处理的:(图片来源于Spring

  • 详解Puppeteer 入门教程

    1.Puppeteer 简介 Puppeteer 是一个node库,他提供了一组用来操纵Chrome的API, 通俗来说就是一个 headless chrome浏览器 (当然你也可以配置成有UI的,默认是没有的).既然是浏览器,那么我们手工可以在浏览器上做的事情 Puppeteer 都能胜任, 另外,Puppeteer 翻译成中文是"木偶"意思,所以听名字就知道,操纵起来很方便,你可以很方便的操纵她去实现: 1) 生成网页截图或者 PDF 2) 高级爬虫,可以爬取大量异步渲染内容的网页

  • 详解React-Todos入门例子

    最近学完React的最基本概念,闲下来的时候就自己写了一个Todo-List的小应用.这里做个简略的说明,给想好好学React的新手看. 开始之前 这里我用了webpackb做了babel和JSX预处理和模块打包.所以对React和一些ES2015(ES6)的语法要有一定的了解.我相信学习ES2015绝对是划算的,因为它是Js的规范.这里给出学习的地方,阮一峰老师的ECMAScript 6 入门或者babel的相关文档Learn ES2015. 最后的实际效果: 我们需要做到的功能有: 可以在最

  • 详解webpack 入门总结和实践(按需异步加载,css单独打包,生成多个入口文件)

    最近在项目中使用了一下webpack,所以这里打算对目前了解的使用方法做一个小小的总结 为什么是webpack 1.webpack一下自己就

  • 详解ECMAScript6入门--Class对象

    面向对象的语言有一个标志,那就是他们都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象. ECMAScript5中没有类的概念,因此它的对象和基于类的语言中的对象有所不同. Javascript生成对象的传统方法是通过构造函数来实现的 function Person(name, age){ this.name = name; this.age = age; this.sayHello = function(){ return "Hello "+ this.name; } }

随机推荐