<Query Kind="Statements">
  <NuGetReference>Microsoft.CodeAnalysis.CSharp</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration.Binder</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration.CommandLine</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration.EnvironmentVariables</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration.FileExtensions</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration.Ini</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration.Json</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration.UserSecrets</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Configuration.Xml</NuGetReference>
  <NuGetReference>Microsoft.Extensions.DependencyInjection</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Logging</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Logging.Configuration</NuGetReference>
  <NuGetReference>Microsoft.Extensions.Options</NuGetReference>
  <NuGetReference>Newtonsoft.Json</NuGetReference>
  <NuGetReference>xunit</NuGetReference>
  <Namespace>Microsoft.Extensions.Configuration</Namespace>
  <Namespace>Microsoft.Extensions.Configuration.CommandLine</Namespace>
  <Namespace>Microsoft.Extensions.Configuration.EnvironmentVariables</Namespace>
  <Namespace>Microsoft.Extensions.Configuration.Memory</Namespace>
  <Namespace>Microsoft.Extensions.DependencyInjection</Namespace>
  <Namespace>Microsoft.Extensions.DependencyInjection.Extensions</Namespace>
  <Namespace>Microsoft.Extensions.FileProviders.Internal</Namespace>
  <Namespace>Microsoft.Extensions.FileProviders.Physical</Namespace>
  <Namespace>Microsoft.Extensions.Logging</Namespace>
  <Namespace>Microsoft.Extensions.Logging.Abstractions</Namespace>
  <Namespace>Microsoft.Extensions.Logging.Configuration</Namespace>
  <Namespace>Microsoft.Extensions.Options</Namespace>
  <Namespace>Microsoft.Extensions.Primitives</Namespace>
  <Namespace>Newtonsoft.Json</Namespace>
  <Namespace>Newtonsoft.Json.Converters</Namespace>
  <Namespace>Newtonsoft.Json.Linq</Namespace>
  <Namespace>Newtonsoft.Json.Serialization</Namespace>
  <Namespace>System.Threading.Tasks</Namespace>
  <IncludePredicateBuilder>true</IncludePredicateBuilder>
  <IncludeLinqToSql>true</IncludeLinqToSql>
  <IncludeAspNet>true</IncludeAspNet>
</Query>

/*
	数据切片学习
*/

/*
	相关类及命名空间
	System.ArraySegment 数组切片
	System.Index 索引对象
	System.Range 范围对象,不支持多维数组
	System.Linq 结构化查询
*/

// 切片语法糖:C# 8+支持

{ // ^ 表示倒数:从尾部向前数,并且从1开始,索引必须是正整数

	var names = new string[] { "潘安琪", "贺睿", "邹致远", "蔡子韬", "江睿", "范震南", "何詩涵", "郝岚", "尹震南", "萧詩涵" };

	//倒数第1个:索引从1开始,而不是0开始(为0则异常)
	Console.WriteLine($"倒数第1个:{names[^1]} ");
	Console.WriteLine($"倒数第2个:{names[^2]} ");
}

{ // .. 表示范围:[开始索引..结束索引]

	var names = new string[] {"潘安琪", "贺睿", "邹致远", "蔡子韬", "江睿", "范震南", "何詩涵", "郝岚", "尹震南", "萧詩涵"};
	
	//.. 表示所有
	names[..].Dump();

	//开始索引s.. 表示第s个开始,直到结尾
	names[1..].Dump();

	//开始索引s..结束索引e 表示第m个开始,直到s结束e(不包括e)
	names[1..5].Dump();
	names[0..1].Dump();
	
	//与^组合使用
	names[^2..].Dump();		//倒数第2个开始,直到结尾(倒数第2个和倒数第1个)
	names[..^2].Dump();	 	//第1个开始,倒数第2个结束(去掉尾部2项)
	names[5..^2].Dump(); 	//第6个开始,倒数第2个结束(去掉前面5个和尾部2项)
	names[^2..^1].Dump(); 	//倒数第2个开始,倒数第1个结束(倒数第2个)
}

{ // .. 范围:可用 Range 对象表示,第n个可用 System.Index 索引对象表示
	var names = new string[] {"潘安琪", "贺睿", "邹致远", "蔡子韬", "江睿", "范震南", "何詩涵", "郝岚", "尹震南", "萧詩涵"};
	
	System.Range r1= ..;
	names[r1].Dump();
	
	System.Range r2 = new System.Range(); //默认项数为0的切片,不是null而是Empty切片
	names[r2].Dump();
	
	var start = new Index(0);//第1个
	var end = new Index(1,true); //倒序索引,倒数第1个
	
	//“索引对象” 组成 “范围对象”
	var query = new System.Range(start,end);
	
	//切片使用 “范围对象”
	var segment = names[query];
	segment.Dump();
}

/*
	重要特性	
*/

{
	//1、切片是由原数组创建的新数组,两个数组本身互相独立、互不影响;
	//   如果数据项是引用对象,因为两个数组虽然各自独立,但引用对象是同一个,这时引用对象本身的修改,会影响两个数组;
	var ages = new int[] {1, 2, 3, 4, 5};
	var s1 = ages[..2];
	//改变切片项的值,原数组保持不变
	s1[0]=-100;
	
	//两个数组本身互相独立、互不影响
	(ages[0] == s1[0]).Dump();

	//数据项是引用对象,对引用对象的修改,都影响
	var persons = new Person[]
	{
		new Person(){Name = "潘安琪", Age = 20},
		new Person(){Name = "贺睿", Age = 36},
		new Person(){Name = "邹致远", Age = 65},
		new Person(){Name = "蔡子韬", Age = 85},
		new Person(){Name = "江睿", Age = 24},
		new Person(){Name = "范震南", Age = 29},
		new Person(){Name = "何詩涵", Age = 11},
		new Person(){Name = "郝岚", Age = 65},
		new Person(){Name = "尹震南", Age = 85},
		new Person(){Name = "萧詩涵", Age = 62},
	};
	
	var segment = persons[1..3];
	
	//persons和segment本身互相独立
	//但 persons[1]segment[0] 是同一个 Person 地址,所以改变一个引用的 Person 时,另一个也引用了同一个对象自然就变
	
	//修改对象属性值
	segment[0].Name="修改";

	Console.WriteLine($"名称相同:{segment[0].Name == persons[1].Name}");
	
}

/*
	切片与System.Span<T> System.Memory<T> 组合使用
*/
{ 
	//原数组使用AsSpan方法;而不应把切片直接给Span
	//把切片直接给Span,此时切片与原数组独立,相当于Span了整个切片而与原数组脱离关系
	var source = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	
	//AsSpan方法,可以把指定切片语法的部分转为Span,这样原数据与Span相关,才能提高性能
	var span1 = source.AsSpan(0..3);
	Console.WriteLine($"Span是原数组的一部分, source[0]{(source[0]==span1[0]?"==":"!=")}span1[0]");
}


/*
	切片与 “列表模式匹配”
*/
{
	int[] source = new int[] { 1, 3, 5, 7, 9 };
	//传统switch语句:switch (变量) => 变量在后,Case 分支语句,目的是选择执行Case分支语句块,无返回值。
	switch (source)
	{
		case [var a, .., 5]://Case后可以使用各种模式匹配
							//业务逻辑
			break;
	}

	//模式匹配switch语句:判断量 switch (变量)=>变量在前,lamda分支语句,目的是选择执行lamda分支语句块,有返回值

	//使用弃元,放弃返回值
	_ = source switch
	{
		[1, ..] => 2, //因为是lamda表达式,所以只能是单条返回语句.不能加{}执行多语句
		[..] => 3,
		_ => 2,
	};
	//返回值给变量
	int t = source switch
	{
		[1, .., 9] a => a[0],
		int[] { Length: >= 5} item => item[4],
		int[]  =>1,
		_ => 0,
	};

	//作为方法体,返回值给方法执行结果
	static int GetSourceLabel<T>(IEnumerable<T> source) => source switch
	{
		string[] {Length:>0}  =>1,
		int[] i and [var a, ..] => 1,
		Array array => 2,
		ICollection<T>{Count:>0} collection  => 2,
		_ => 0,
	};
}

class Person
{
	public string Name { get; set;}

	public int Age {get;set;}
}