master
bicijinlian 6 years ago
parent 15c2df7a18
commit 6e181771a2

@ -0,0 +1,43 @@
# Linq To Object
> Linq To Object是操作内存对象。
>
> 使用前提对象必须实现IEnumerable或`IEnumerable<T>`接口。
>
> 因为IQueryable和`IQueryable<T>`也实现了IEnumerable或`IEnumerable<T>接口`所以也可以使用Linq To Object。
> 泛型集合均实现了`IEnumerable<T>`接口,可以直接使用。
> 一些集合类,也提供了转换扩展方法,可以转换后使用。
>
## Linq To Object本质
> 本质是扩展方法,没有相应的 Linq Provider这点与 Linq To SQL不同。
## 注意事项
+ 延时执行
> 写好操作步骤时,只是进行了“定义”,直到调用(转换方法、聚合方法会立即执行)时才会真正执行操作。这点特别注意。
+ 异常
> 当对象为null时通常都会抛出“参数null值”异常。使用前就确保对象不为null
``` csharp
[Fact]
public void Null_Test()
{
List<Person> person = null;
//对Linq操作符而言基本上数据源为Null时将引发异常。
Assert.ThrowsAny<ArgumentNullException>(() =>
{
//此处引发异常
var query = person.Where(p => p == null);
});
}
```
+ 操作结果
> 当操作结果没有数据项时不是返回null,而是返回“0数据项”的IEnumerable对象。对结果**不用进行null值判断**

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Linq.Expressions;
using FluentAssertions;
using Xunit;
namespace LinqStudy.Test.LinqToObject
{
/// <summary>
/// 基本项测试
/// </summary>
public class BaseTest
{
/// <summary>
/// 数据源为 Null,引发异常.
/// </summary>
/// <exception cref="ArgumentNullException">
/// ArgumentNullException
/// </exception>
/// <remarks>
/// 对Linq操作符而言数据源为Null时均引发异常。
/// </remarks>
[Fact]
public void DataSource_IsNull_Test()
{
List<Person> person = null;
Assert.ThrowsAny<ArgumentNullException>(() =>
{
//引发异常
var query = person.Where(p => p == null);
});
}
/// <summary>
/// 数据源数据项为0时,不会引发异常.
/// </summary>
[Fact]
public void DataSource_Item_0_Test()
{
List<Person> person = new List<Person>();
//数据源为没有任何内容项时,即 Count=0不会引发异常。
Action action = () =>
{
//查不到任何数据不返回null而是返回 Count=0的对象。
person.Where(p => p == null).ToList();
};
//不引发异常
action.Should().NotThrow();
}
/// <summary>
/// 数据源数据项为0时查询等操作不返回null,而返回“0数据项的”IEnumerable<T>对象。
/// </summary>
[Fact]
public void DataSource_Item0_Return_Test()
{
List<Person> person = new List<Person>();
//数据源为没有任何内容项时,即 Count=0不会引发异常。
Action action = () =>
{
//查不到任何数据不返回null而是返回 Count=0的对象。
person.Where(p => p == null).ToList();
};
//不引发异常
action.Should().NotThrow();
}
/// <summary>
/// 查询不到数据项时不返回null,而是返回“0数据项的”IEnumerable<T>对象
/// </summary>
[Fact]
public void NoQueryItem_Return_Test()
{
List<Person> person = new List<Person>()
{
new Person(){ Id=1,Name="小屁孩",Age=87},
new Person(){ Id=2,Name="小屁孩",Age=45},
new Person(){ Id=3,Name="小屁孩",Age=55},
new Person(){ Id=4,Name="小屁孩",Age=23},
};
//查不到数据时返回Count=0的IEnumerable<T>对象
var result = person.Where(p => p.Age < 10).ToList();
Assert.Empty(result);
}
}
}

@ -0,0 +1,11 @@
using System;
namespace LinqStudy.Test.LinqToObject
{
/// <summary>
/// 生成操作符
/// </summary>
public class CreateTest
{
}
}

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
namespace LinqStudy.Test.LinqToObject
{
public class OtherTest
{
/// <summary>
/// is操作符用作if条件时判断之后可以直接赋值给一个变量.(输出给变量)
/// 其它地方可以用as实现相同功能
/// </summary>
/// <example>
/// if (id is List-int output){output.Add(1);}
/// </example>
[Fact]
public void Is_Test()
{
List<int> id = new List<int>();
if (id is List<int> output)
{
output.Add(1);
}
var cc = id as List<int>;
cc.Add(1);
}
}
}

@ -0,0 +1,168 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using LinqStudy;
namespace LinqStudy.Test.LinqToObject
{
/// <summary>
/// 投影操作符
/// 投影:遍历序列中的元素,将元素由一种类型转换为另一种类型的操作,并返回由转换后元素组成的新序列。
/// 即是IEnumerable<TSource> => IEnumerable<TResult>
/// </summary>
public class ProjectiveTest
{
/// <summary>
/// Select投影简单投影一对一
/// </summary>
[Fact]
public void Select_Test()
{
// Arrange
var persons = PersonManager.GetPersons();
// Act
var maps = persons.Select(p=>p.Age).ToList();
// Assert
Assert.IsType<List<int>>(maps);
}
/// <summary>
/// 投影为匿名类
/// </summary>
[Fact]
public void Select_Anonymous_Test()
{
// Arrange
var persons = PersonManager.GetPersons();
// Act
var maps = persons.Select(p=>new {Id=p.Id, Node=$"姓名{p.Name},年龄{p.Age}."}).ToList();
// Assert
Assert.IsNotType<List<Person>>(maps);
}
/// <summary>
/// 投影传入索引(序号)参数
/// </summary>
[Fact]
public void Select_Index_Test()
{
var persons = PersonManager.GetPersons();
var maps = persons.Select((query,index)=> new KeyValuePair<int, Person>(index,query)).ToList();
var indexs = persons.Select((query, index) => index).ToList();
Assert.IsType<List<KeyValuePair<int, Person>>>(maps);
Assert.Equal(0,indexs[0]);
}
/// <summary>
/// SelectMany:复合投影,一对多,合并多到一个集合。
/// 枚举源序列,将源序列每一项投影为新的集合,合并所有新集合为一个可枚举序列,做为返回值;
/// 提供了将多个 from子句组合起来的功能它将每个对象的结果合并成单个可枚举序列。
/// </summary>
[Fact]
public void SelectMany_Test()
{
var employees = new List<Employee>()
{
new Employee(){Id=1,Name="小明",Emails=new List<string>(){ "abc@163.com", "acd@163.com", "ade@163.com" } },
new Employee(){Id=2,Name="大壮",Emails=new List<string>(){ "bbc@163.com", "bcd@163.com", "bde@163.com" } },
new Employee(){Id=3,Name="周羊",Emails=new List<string>(){ "cbc@163.com", "ccd@163.com", "cde@163.com" } },
new Employee(){Id=4,Name="承承",Emails=new List<string>(){ "dbc@163.com", "dcd@163.com", "dde@163.com" } },
new Employee(){Id=5,Name="东升",Emails=new List<string>(){ "ebc@163.com", "ecd@163.com", "ede@163.com" }},
};
var maps = employees.SelectMany(q=>q.Emails).ToList();
Assert.IsType<List<string>>(maps);
Assert.Equal(15, maps.Count);
}
/// <summary>
/// 投影传入索引(序号)参数
/// </summary>
[Fact]
public void SelectMany_Index_Test()
{
var employees = new List<Employee>()
{
new Employee(){Id=1,Name="小明",Emails=new List<string>(){ "abc@163.com", "acd@163.com", "ade@163.com" } },
new Employee(){Id=2,Name="大壮",Emails=new List<string>(){ "bbc@163.com", "bcd@163.com", "bde@163.com" } },
new Employee(){Id=3,Name="周羊",Emails=new List<string>(){ "cbc@163.com", "ccd@163.com", "cde@163.com" } },
new Employee(){Id=4,Name="承承",Emails=new List<string>(){ "dbc@163.com", "dcd@163.com", "dde@163.com" } },
new Employee(){Id=5,Name="东升",Emails=new List<string>(){ "ebc@163.com", "ecd@163.com", "ede@163.com" }},
};
var maps = employees.SelectMany((q, idx) =>
{
q.Emails.Add(idx.ToString());
return q.Emails;
}).ToList();
Assert.IsType<List<string>>(maps);
Assert.Equal(20, maps.Count);
}
/// <summary>
/// 自定义结果项:源项与源项选择的集合项,一一组合,组成新自定义序列。
/// 类似Cross JOIN
/// </summary>
[Fact]
public void SelectMany_TCollection_Test()
{
var employees = new List<Employee>()
{
new Employee(){ Id=1,Name="小明",Emails=new List<string>(){ "a1@163.com", "a2@163.com", "a3@163.com" } },
new Employee(){ Id=2,Name="大壮",Emails=new List<string>(){ "b1@163.com", "b2@163.com", "b3@163.com" } },
new Employee(){ Id=3,Name="周羊",Emails=new List<string>(){ "c1@163.com", "c2@163.com", "c3@163.com" } },
new Employee(){ Id=4,Name="承承",Emails=new List<string>(){ "d1@163.com", "d2@163.com", "d3@163.com" } },
new Employee(){ Id=5,Name="东升",Emails=new List<string>(){ "e1@163.com", "e2@163.com", "e3@163.com" } },
};
var maps = employees.SelectMany((employee)=> employee.Emails,(person,email)=> new { Name=person.Name,Email=email}).ToList();
Assert.Equal(15, maps.Count);
}
/// <summary>
/// 自定义结果项:带索引
/// 类似Cross JOIN
/// </summary>
[Fact]
public void SelectMany_TCollection_Index_Test()
{
var employees = new List<Employee>()
{
new Employee(){ Id=1,Name="小明",Emails=new List<string>(){ "a1@163.com", "a2@163.com", "a3@163.com" } },
new Employee(){ Id=2,Name="大壮",Emails=new List<string>(){ "b1@163.com", "b2@163.com", "b3@163.com" } },
new Employee(){ Id=3,Name="周羊",Emails=new List<string>(){ "c1@163.com", "c2@163.com", "c3@163.com" } },
new Employee(){ Id=4,Name="承承",Emails=new List<string>(){ "d1@163.com", "d2@163.com", "d3@163.com" } },
new Employee(){ Id=5,Name="东升",Emails=new List<string>(){ "e1@163.com", "e2@163.com", "e3@163.com" } },
};
var maps = employees.SelectMany
(
(employee, idx) =>
{
return new List<Employee>() { new Employee() { Id = employee.Id, Name = employee.Name + "_" + idx, Emails = employee.Emails } };
},
(person,email) => new
{
Name = email.Name,
Email = email.Emails
}
)
.ToList();
Assert.Equal(5, maps.Count);
}
}
}

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace LinqStudy
{
/// <summary>
/// 雇员
/// </summary>
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Emails { get; set; }
}
}
Loading…
Cancel
Save