一、C#6中新增的功能

get 只读属性

简洁的语法来创建不可变类型,仅有get访问器:

public string FirstName { get; }
public string LastName { get; }

当然很多时候,我们使用的是私有化来设置set。

然后通过构造函数来赋值:

public Student(string firstName, string lastName)
{
if (IsNullOrWhiteSpace(lastName))
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
FirstName = firstName;
LastName = lastName;
}

get 属性初始化表达式

在属性声明中声明自动属性的初始值,

public ICollection<double> Grades { get; } = new List<double>();

声明处就可以直接被初始化。

Expression-bodied 函数成员

这适用于方法和只读属性。 例如,重写 ToString() 通常是理想之选:

public override string ToString() => $"{LastName}, {FirstName}";

也可以将此语法用于只读属性:

public string FullName => $"{FirstName} {LastName}";

using 静态命名空间

using static  增强功能可用于导入单个类的静态方法。 指定要使用的类:

using static System.Math;

在 LINQ 查询中会经常看到这种情况。 可以通过导入 Enumerable 或 Queryable 来导入 LINQ 模式。

Null 条件运算符

Null 条件运算符使 null 检查更轻松、更流畅  。 将成员访问 . 替换为 ?.

var first = person?.FirstName;

如果person为空,返回的值就是null,是string的默认值,如果FirstName是int类型,那返回的就是int的默认值0。

$ 字符串内插

新的字符串内插功能可以在字符串中嵌入表达式。 使用 $ 作为字符串的开头,并使用 { 和  } 之间的表达式代替序号:

public string GetGradePointPercentage() => $"Name: {LastName}, {FirstName}. G.P.A: {Grades.Average():F2}";

上一行代码将 Grades.Average() 的值格式设置为具有两位小数的浮点数。

when 异常筛选器

“异常筛选器”是确定何时应该应用给定的catch子句的子句 。如果用于异常筛选器的表达式计算结果为true,则catch子句将对异常执行正常处理。 如果表达式计算结果为false,则将跳过 catch子句。一种用途是检查有关异常的信息,以确定catch子句是否可以处理该异常:

public static async Task<string> MakeRequest()
{
WebRequestHandler webRequestHandler = new WebRequestHandler();
webRequestHandler.AllowAutoRedirect = false;
using (HttpClient client = new HttpClient(webRequestHandler))
{
var stringTask = client.GetStringAsync("https://docs.microsoft.com/en\-us/dotnet/about/");
try
{
var responseText = await stringTask;
return responseText;
}
catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
{
return "Site Moved";
}
}
}

nameof 表达式

nameof 表达式的计算结果为符号的名称。 每当需要变量、属性或成员字段的名称时,这是让工具正常运行的好办法,说白了就是更好的重构:

if (IsNullOrWhiteSpace(lastName))
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));

Catch 和 Finally 块中的 Await

现在可以在 catch 或 finally 表达式中使用  await。 这通常用于日志记录方案:

public static async Task<string> MakeRequestAndLogFailures()
{
await logMethodEntrance();
var client = new System.Net.Http.HttpClient();
var streamTask = client.GetStringAsync("https://localHost:10000");
try {
var responseText = await streamTask;
return responseText;
} catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
{
await logError("Recovered from redirect", e);
return "Site Moved";
}
finally
{
await logMethodExit();
client.Dispose();
}
}

索引器初始化关联集合

可以将集合初始值设定项与 Dictionary<TKey,TValue> 集合和其他类型一起使用,在这种情况下,可访问的 Add 方法接受多个参数。 新语法支持使用索引分配到集合中:

private Dictionary<int, string> webErrors = new Dictionary<int, string> {
[404] = "Page not Found",
[302] = "Page moved, but left a forwarding address.",
[500] = "The web server can't come out to play today." };

二、C#7.x 中新增的功能

out 变量

可以在方法调用的参数列表中声明 out 变量,而不是编写单独的声明语句:

if (int.TryParse(input, out int result))
Console.WriteLine(result);
else
Console.WriteLine("Could not parse input");

为清晰明了,可能需指定 out 变量的类型,如上所示。 但是,该语言支持使用隐式类型的局部变量:

if (int.TryParse(input, out var answer))
Console.WriteLine(answer);
else
Console.WriteLine("Could not parse input");

Tuple 元组

低于 C# 7.0 的版本中也提供元组,但它们效率低下且不具有语言支持。这意味着元组元素只能作为 Item1 和 Item2 等引用。

可以通过为每个成员赋值来创建元组,并可选择为元组的每个成员提供语义名称:

(string Alpha, string Beta) namedLetters = ("a", "b");
Console.WriteLine($"{namedLetters.Alpha}, {namedLetters.Beta}");

在进行元组赋值时,还可以指定赋值右侧的字段的名称:

var alphabetStart = (Alpha: "a", Beta: "b");
Console.WriteLine($"{alphabetStart.Alpha}, {alphabetStart.Beta}");

使用的时候,可以直接点出来:

alphabetStart.Alpha
alphabetStart.Beta

_ 弃元

C# 增添了对弃元的支持。 弃元是一个名为 _(下划线字符)的只写变量,可向单个变量赋予要放弃的所有值。 弃元类似于未赋值的变量;不可在代码中使用弃元(赋值语句除外):

public class Example
{
public static void Main()
{
var (_, _, _, pop1, _, pop2) = QueryCityDataForYears("New York City", 1960, 2010); Console.WriteLine($"Population change, 1960 to 2010: {pop2 \- pop1:N0}");
} private static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int year2)
{
int population1 = 0, population2 = 0;
double area = 0; if (name == "New York City")
{
area = 468.48;
if (year1 == 1960)
{
population1 = 7781984;
}
if (year2 == 2010)
{
population2 = 8175133;
}
return (name, area, year1, population1, year2, population2);
} return ("", 0, 0, 0, 0, 0);
}
}

is 模式匹配

模式匹配支持 is 表达式和 switch 表达式。 每个表达式都允许检查对象及其属性以确定该对象是否满足所寻求的模式。 使用 when 关键字来指定模式的其他规则:

public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
int sum = 0;
foreach (var i in sequence)
{
switch (i)
{
case 0:
break;
case IEnumerable<int> childSequence:
{
foreach(var item in childSequence)
sum += (item > 0) ? item : 0;
break;
}
case int n when n > 0:
sum += n;
break;
case null:
throw new NullReferenceException("Null found in sequence");
default:
throw new InvalidOperationException("Unrecognized type");
}
}
return sum;
}
  • case 0: 是常见的常量模式。
  • case IEnumerable<int> childSequence: 是一种类型模式。
  • case int n when n > 0: 是具有附加 when 条件的类型模式。
  • case null: 是 null 模式。
  • default: 是常见的默认事例。

本地函数(内部)

本地函数使你能够在另一个方法的上下文内声明方法。 本地函数使得类的阅读者更容易看到本地方法仅从声明它的上下文中调用。

public static IEnumerable<char> AlphabetSubset3(char start, char end)
{
if (start < 'a' || start > 'z')
throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter");
if (end < 'a' || end > 'z')
throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter"); if (end <= start)
throw new ArgumentException($"{nameof(end)} must be greater than {nameof(start)}"); return alphabetSubsetImplementation(); IEnumerable<char> alphabetSubsetImplementation()
{
for (var c = start; c < end; c++)
yield return c;
}
}

注意上边的alphabetSubsetImplementation 方法,是在内部定义的。

同样可以使用异步:

public Task<string> PerformLongRunningWork(string address, int index, string name)
{
if (string.IsNullOrWhiteSpace(address))
throw new ArgumentException(message: "An address is required", paramName: nameof(address));
if (index < 0)
throw new ArgumentOutOfRangeException(paramName: nameof(index), message: "The index must be non\-negative");
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException(message: "You must supply a name", paramName: nameof(name)); return longRunningWorkImplementation(); async Task<string> longRunningWorkImplementation()
{
var interimResult = await FirstWork(address);
var secondResult = await SecondStep(index, name);
return $"The results are {interimResult} and {secondResult}. Enjoy.";
}
}

当然也支持某些使用lambda表达式来完成。

数字文本语法改进

C# 7.0 包括两项新功能,可用于以最可读的方式写入数字来用于预期用途:二进制文本和数字分隔符 。在创建位掩码时,或每当数字的二进制表示形式使代码最具可读性时,以二进制形式写入该数字:

public const int Sixteen = 0b0001_0000;
public const int ThirtyTwo = 0b0010_0000;
public const int SixtyFour = 0b0100_0000;
public const int OneHundredTwentyEight = 0b1000_0000;

常量开头的 0b 表示该数字以二进制数形式写入。 二进制数可能会很长,因此通过引入 _ 作为数字分隔符通常更易于查看位模式,如上面二进制常量所示。 数字分隔符可以出现在常量的任何位置。 对于十进制数字,通常将其用作千位分隔符:

public const long BillionsAndBillions = 100_000_000_000;

三、C#8.0中新增的功能

“.NET Core 3.x”和“.NET Standard 2.1”支持 C# 8.0;

Readonly 成员

可将 readonly 修饰符应用于结构的成员。 它指示该成员不会修改状态。 这比将 readonly 修饰符应用于 struct 声明更精细。  请考虑以下可变结构:

public readonly double Distance => Math.Sqrt(X \* X + Y \* Y);

默认接口方法

现在可以将成员添加到接口,并为这些成员提供实现。 借助此语言功能,API 作者可以将方法添加到以后版本的接口中,而不会破坏与该接口当前实现的源或二进制文件兼容性。 现有的实现继承默认实现。

public interface ICustomer
{
IEnumerable<IOrder> PreviousOrders { get; } DateTime DateJoined { get; }
DateTime? LastOrder { get; }
string Name { get; }
IDictionary<DateTime, string> Reminders { get; }
}

Switch 表达式升级

通常情况下,switch 语句在其每个 case 块中生成一个值。借助 Switch 表达式,可以使用更简洁的表达式语法。

public static RGBColor FromRainbowClassic(Rainbow colorBand)
{
switch (colorBand)
{
case Rainbow.Red:
return new RGBColor(0xFF, 0x00, 0x00);
case Rainbow.Orange:
return new RGBColor(0xFF, 0x7F, 0x00);
case Rainbow.Yellow:
return new RGBColor(0xFF, 0xFF, 0x00);
case Rainbow.Green:
return new RGBColor(0x00, 0xFF, 0x00);
case Rainbow.Blue:
return new RGBColor(0x00, 0x00, 0xFF);
case Rainbow.Indigo:
return new RGBColor(0x4B, 0x00, 0x82);
case Rainbow.Violet:
return new RGBColor(0x94, 0x00, 0xD3);
default:
throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand));
};
}

这里有几个语法改进:

  • 变量位于 switch 关键字之前。 不同的顺序使得在视觉上可以很轻松地区分 switch 表达式和 switch 语句。
  • 将 case 和 : 元素替换为 =>。 它更简洁,更直观。
  • 将 default 事例替换为 _ 弃元。
  • 正文是表达式,不是语句。
public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
_ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};

属性模式

借助属性模式,可以匹配所检查的对象的属性。 请看一个电子商务网站的示例,该网站必须根据买家地址计算销售税。 这种计算不是 Address 类的核心职责。 它会随时间变化,可能比地址格式的更改更频繁。 销售税的金额取决于地址的 State 属性。 下面的方法使用属性模式从地址和价格计算销售税:

public static decimal ComputeSalesTax(Address location, decimal salePrice) =>
location switch
{
{ State: "WA" } => salePrice \* 0.06M,
{ State: "MN" } => salePrice \* 0.075M,
{ State: "MI" } => salePrice \* 0.05M,
// other cases removed for brevity...
_ => 0M
};

在 LINQ 查询中会经常看到这种情况。 可以通过导入 Enumerable 或 Queryable 来导入 LINQ 模式。

元组模式

一些算法依赖于多个输入。 使用元组模式,可根据表示为元组的多个值进行切换。  以下代码显示了游戏“rock, paper, scissors(石头剪刀布)”的切换表达式::

public static string RockPaperScissors(string first, string second)
=> (first, second) switch
{
("rock", "paper") => "rock is covered by paper. Paper wins.",
("rock", "scissors") => "rock breaks scissors. Rock wins.",
("paper", "rock") => "paper covers rock. Paper wins.",
("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
("scissors", "rock") => "scissors is broken by rock. Rock wins.",
("scissors", "paper") => "scissors cuts paper. Scissors wins.",
(_, _) => "tie"
};

如果person为空,返回的值就是null,是string的默认值,如果FirstName是int类型,那返回的就是int的默认值0。

using 声明

using 声明是前面带 using 关键字的变量声明。 它指示编译器声明的变量应在封闭范围的末尾进行处理。 以下面编写文本文件的代码为例:

static int WriteLinesToFile(IEnumerable<string> lines)
{
using var file = new System.IO.StreamWriter("WriteLines2.txt");
// Notice how we declare skippedLines after the using statement.
int skippedLines = 0;
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else
{
skippedLines++;
}
}
// Notice how skippedLines is in scope here.
return skippedLines;
// file is disposed here
}

前面的代码相当于下面使用经典 using 语句的代码:

static int WriteLinesToFile(IEnumerable<string> lines)
{
// We must declare the variable outside of the using block
// so that it is in scope to be returned.
int skippedLines = 0;
using (var file = new System.IO.StreamWriter("WriteLines2.txt"))
{
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else {
skippedLines++;
}
}
return skippedLines;
} // file is disposed here
}

Static 静态本地函数

现在可以向本地函数添加 static 修饰符,以确保本地函数不会从封闭范围捕获(引用)任何变量。

int M()
{
int y = 5;
int x = 7;
return Add(x, y);
static int Add(int left, int right) => left + right;
}

async 异步流

从 C# 8.0 开始,可以创建并以异步方式使用流。返回异步流的方法有三个属性:

. 它是用 async 修饰符声明的。

. 它将返回 IAsyncEnumerable。

. 该方法包含用于在异步流中返回连续元素的 yield return 语句。

public static async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()
{
for (int i = 0; i < 20; i++)
{
await Task.Delay(100);
yield return i;
}
} await foreach (var number in GenerateSequence())
{
Console.WriteLine(number);
}

异步可释放:

从 C# 8.0 开始,语言支持实现 System.IAsyncDisposable 接口的异步可释放类型。可使用 await using 语句来处理异步可释放对象。

索引和范围

范围指定范围的开始和末尾 。 包括此范围的开始,但不包括此范围的末尾,这表示此范围包含开始但不包含末尾 。 范围 [0..^0] 表示整个范围,就像 [0..sequence.Length] 表示整个范围。

请看以下几个示例。 请考虑以下数组,用其顺数索引和倒数索引进行注释:

var words = new string[]
{
// index from start index from end
"The", // 0 ^9
"quick", // 1 ^8
"brown", // 2 ^7
"fox", // 3 ^6
"jumped", // 4 ^5
"over", // 5 ^4
"the", // 6 ^3
"lazy", // 7 ^2
"dog" // 8 ^1
}; // 9 (or words.Length) ^0 // 可以使用 ^1 索引检索最后一个词:
Console.WriteLine($"The last word is {words[^1]}");
// writes "dog"

以下代码创建了一个包含单词“quick”、“brown”和“fox”的子范围。 它包括 words[1] 到 words[3]。 元素 words[4] 不在该范围内。

var quickBrownFox = words[1..4];

var allWords = words[..]; // contains "The" through "dog".
var firstPhrase = words[..4]; // contains "The" through "fox"
var lastPhrase = words[6..]; // contains "the", "lazy" and "dog"

null 合并赋值

C# 8.0 引入了 null 合并赋值运算符 ??=。 仅当左操作数计算为 null 时,才能使用运算符 ??= 将其右操作数的值分配给左操作数。

List<int> numbers = null;
int? i = null; numbers ??= new List<int>();
numbers.Add(i ??= 17);
numbers.Add(i ??= 20); Console.WriteLine(string.Join(" ", numbers)); // output: 17 17
Console.WriteLine(i); // output: 17

四、C#9.0 中新增的功能

.NET5支持C#9.0.

记录类型

C# 9.0 引入了记录类型,这是一种引用类型,它提供合成方法来提供值语义,从而实现相等性。 默认情况下,记录是不可变的。

public record Person
{
public string LastName { get; }
public string FirstName { get; } public Person(string first, string last)
=> (FirstName, LastName) = (first, last);
}

Init 仅限的资源库

从 C# 9.0 开始,可为属性和索引器创建 init 访问器,而不是 set 访问器。 调用方可使用属性初始化表达式语法在创建表达式中设置这些值,但构造完成后,这些属性将变为只读。 仅限 init 的资源库提供了一个窗口用来更改状态。

public struct WeatherObservation
{
public DateTime RecordedAt { get; init; }
public decimal TemperatureInCelsius { get; init; }
public decimal PressureInMillibars { get; init; } public override string ToString() =>
$"At {RecordedAt:h:mm tt} on {RecordedAt:M/d/yyyy}: " +
$"Temp = {TemperatureInCelsius}, with {PressureInMillibars} pressure";
}

调用方可使用属性初始化表达式语法来设置值,同时仍保留不变性:

var now = new WeatherObservation
{
RecordedAt = DateTime.Now,
TemperatureInCelsius = 20,
PressureInMillibars = 998.0m
};

顶级语句

顶级语句从许多应用程序中删除了不必要的流程。只有一行代码执行所有操作。 借助顶级语句,可使用 using 语句和执行操作的一行替换所有样本:

using System;
Console.WriteLine("Hello World!");

如果需要单行程序,可删除 using 指令,并使用完全限定的类型名称:

System.Console.WriteLine("Hello World!");

模式匹配增强功能

C# 9 包括新的模式匹配改进:

  • 类型模式要求在变量是一种类型时匹配
  • 带圆括号的模式强制或强调模式组合的优先级
  • 联合 and 模式要求两个模式都匹配
  • 析取 or 模式要求任一模式匹配
  • 求反 not 模式要求模式不匹配
  • 关系模式要求输入小于、大于、小于等于或大于等于给定常数。
public static bool IsLetter(this char c) =>
c is >= 'a' and <= 'z' or >= 'A' and <= 'Z'; public static bool IsLetterOrSeparator(this char c) =>
c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ',';

调试和完成功能

在 C# 9.0 中,已知创建对象的类型时,可在 new 表达式中省略该类型。 最常见的用法是在字段声明中:

private List<WeatherObservation> _observations = new();

当需要创建新对象作为参数传递给方法时,也可使用目标类型 new

C#从6.0~9.0都更新了什么?的更多相关文章

  1. Jmeter3.0发布,版本更新都更新了什么

    Jmeter已发布了3.0,一个大版本的开源测试工具,加入了一些新的特性及软件的改进. Jmeter已隔10年的大版本更新 这是在过去12年里jmeter第一个大版本的更新,jmeter 2.0版本发 ...

  2. Python 3.X简史——记录3.0之后的重要更新

    Python 3.0在2008年12月3日正式发布,在之后又经历了多个小版本(3.1,3.2,3.3……),本文梳理Python 3.0之后的新特性. 其实每个版本都有大量更新,都写出来要几百页,这里 ...

  3. [wxWidgets]_[0基础]_[经常更新进度条程序]

    场景: 1. 非常根据程序的进展需要处理业务,以更新进度条,进度条的目的是为了让用户知道业务流程的进度.一个进度条程序更友好,让用户知道在程序执行.不是没有反应. 2. 现在更新见过这两种方法的进展. ...

  4. Ibatis 3.0 之前使用的都是2.0 3.0与2.0的内容有很大的不同

    以前用过ibatis2,但是听说ibatis3有较大的性能提升,而且设计也更合理,他不兼容ibatis2.尽管ibatis3还是beta10的状态,但还是打算直接使用ibatis3.0, ibatis ...

  5. 盘点 React 16.0 ~ 16.5 主要更新及其应用

    目录 0. 生命周期函数的更新 1. 全新的 Content API 2. React Strict Mode 3. Portal 4. Refs 5. Fragment 6. 其他 7. 总结 生命 ...

  6. ElasticSearch5.0+版本分词热更新实践记录

    前言 刚开始接触ElasticSearch的时候,版本才是2.3.4,短短的时间,现在都更新到5.0+版本了.分词和head插件好像用法也不一样了,本博客记录如何配置Elasticsearch的Hea ...

  7. Fundebug 微信小游戏异常监控插件更新至 0.5.0,支持监控 HTTP 慢请求

    摘要: 支持监控 HTTP 慢请求,同时修复了记录的 HTTP 响应时间偏小的 BUG. Fundebug是专业微信小游戏 BUG 监控服务,可以第一时间捕获线上环境中小游戏的异常.错误或者 BUG, ...

  8. Fundebug后端Node.js插件更新至0.2.0,支持监控Express慢请求

    摘要: 性能问题也是BUG,也需要监控. Fundebug后端Node.js异常监控服务 Fundebug是专业的应用异常监控平台,我们Node.js插件fundebug-nodejs可以提供全方位的 ...

  9. Fundebug录屏插件更新至0.5.0,新增domain参数

    摘要: 通过配置domain来保证"视频"的正确录制 录屏功能介绍 Fundebug提供专业的异常监控服务,当线上应用出现 BUG 的时候,我们可以第一时间报警,帮助开发者及时发现 ...

  10. 重大更新!Druid 0.18.0 发布—Join登场,支持Java11

    Apache Druid本质就是一个分布式支持实时数据分析的数据存储系统. 能够快速的实现查询与数据分析,高可用,高扩展能力. 距离上一次更新刚过了二十多天,距离0.17版本刚过了三个多月,Druid ...

随机推荐

  1. 张同乐-从零开始,打造高效可靠的Locust性能测试

    一.前言 欢迎来到Locust负载测试的世界!Locust是一款开源的负载测试工具,它可以模拟成千上万的用户同时访问你的应用程序,以测试其性能和稳定性. 这个工具具有易于使用.可扩展和高度可定制化等特 ...

  2. vue-element-admin 运行踩坑笔记

      npm WARN deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x. npm E ...

  3. Vue cli之项目执行流程

    整个项目是一个主文件index.html,index.html中会引入src文件夹中的main.js,main.js中会导入顶级单文件组件App.vue,App.vue中会通过组件嵌套或者路由来引用其 ...

  4. python利用flux基本读写influxDB

    1.读取 QuerApi 形式 python 利用 flux 语句查询 influxdb 数据. https://influxdb-client.readthedocs.io/en/latest/ap ...

  5. P9174

    problem & blog 子任务 \(1\) 和子任务 \(2\) 都比较好做.所以我们这里不讲. 状态将是数字 \(n\) (每个颜色的频率的排序数组)的所有分区,因为当我们旋转每种颜色 ...

  6. ABC317题解报告

    我直接从第三题开始讲了. T3 把数组 \(A\) 从大到小排序. 然后从前往后把前 \(q\) 个数加起来,然后判断这 \(q\) 个数的和与 \(d\) 的大小关系,如果大了就变成 \(d\). ...

  7. 借助 DSL 来简化 Loadgen 配置

    引言 在上篇文章中,我们介绍了如何用 Loadgen 来简化 HTTP API 的集成测试.在实际使用中会发现,编写测试时最令人"头疼"的部分是设计测试的输入和校验程序的输出,而针 ...

  8. Spring Data JPA 学习笔记1 - JPA与Spring Data

    标记[跳过]的未来完善 1 理解JPA 1.1 什么是持久化? 当一个软件关闭的时候,软件内储存的状态数据还能在下次开启时被恢复,这就是持久化.对象持久化是指每个独立的对象的生命周期都能不依赖应用程序 ...

  9. nordic—RTC+PPI定时驱动某外设做非单次触发(本次测试为驱动GPIO口做电平翻转)

    简介:在nordic的开发中使用到RTC时,对于比较通道0/1/2/3的中断来说,如果不进行相关配置(如SDK中例子,使用的RTC比较通道就只能触发一次,不能多次触发),会导致比较中断只进入一次,如果 ...

  10. 增补博客 第六篇 python 电子算盘

    珠算测试器 题目描述]设计一个珠算测试器,要求能够完成珠算加减法的测试.具体的要求功能如下:(1)用户启动测试,输入用户名后系统随机生成特定数目的加减法测试题:(2) 要求测试使用表盘式或数字时秒表进 ...