在这个帖子中,我们将探讨 C# 12 中新增的 “默认 lambda 参数” 功能,让开发者能够在 lambda 表达式中直接指定默认值。
默认 lambda 参数 🧮
在 C# 12 之前,如果你需要在 lambda 表达式中提供某种默认行为,通常会使用 ??
(null-coalescing 操作符)或 ?:
(条件操作符)。看下面的例子:
var IncrementBy = static (int source, int? increment) => {
// 等同于 source + (increment.HasValue ? increment.Value : 1)
return source + (increment ?? 1);
};
Console.WriteLine(IncrementBy(5, null)); // 6
Console.WriteLine(IncrementBy(5, 2)); // 7
C# 12 之后 🤓
现在,有了默认 lambda 参数,你可以在 lambda 表达式中直接为参数定义默认值。默认参数的语法类似于方法中的默认参数。默认值紧跟在参数名后面,用等号(=
)分隔。例如:
var IncrementBy = static (int source, int increment = 1) => {
return source + increment;
};
Console.WriteLine(IncrementBy(10)); // 11
Console.WriteLine(IncrementBy(10, 20)); // 30
lambda 表达式的默认参数规则与方法相同:默认值必须是编译时常量,并且类型必须与参数一致。默认值在 编译时 计算,调用 lambda 表达式时参数是可选的。
delegate int (int arg1, int arg2 = 1);
这意味着当你在调用 lambda 时理论上可以只提供参数名称,但实际上是匿名函数生成的名称。比如,考虑下面扩展的例子:
var IncrementByWithOffset = static (int source, int increment = 1, int offset = 100) => {
return source + increment + offset;
};
Console.WriteLine(IncrementByWithOffset(10)); // 111
Console.WriteLine(IncrementByWithOffset(10, 20)); // 130
Console.WriteLine(IncrementByWithOffset(10, 20, 0)); // 30
Console.WriteLine(IncrementByWithOffset(10, arg2: -100)); // 10
Console.WriteLine(IncrementByWithOffset(10, arg3: 0)); // 11
ASP.NET Core Minimal API 示例 🌐
让我们看一个使用默认 lambda 参数的 ASP.NET Core Minimal API 示例。在 Visual Studio 2022 中,通过文件 > 新建 > 项目 对话框创建一个新的ASP.NET Core Web API项目。或者,你可以使用以下.NET CLI 命令创建新项目:
dotnet new webapi -n WebApi
这个模板创建了一个带有单个 /weatherforecast
端点的 ASP.NET Core Web API 项目。/weatherforecast
端点返回五个随机天气预报,来看看模板代码中的 Program.cs
文件:
var builder = WebApplication.CreateBuilder(args);
// 添加服务到容器...
// 更多关于配置Swagger/OpenAPI的信息:https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// 配置HTTP请求管道...
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
app.MapGet("/weatherforecast", () => {
var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
)).ToArray();
return forecast;
}).WithName("GetWeatherForecast").WithOpenApi();
app.Run();
这里有些模板代码,我们关注的重点是 MapGet
功能,因为它将我们的 lambda 功能映射到 HTTP GET 请求。
app.MapGet("/weatherforecast", () => {
var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
)).ToArray();
return forecast;
}).WithName("GetWeatherForecast").WithOpenApi();
/weatherforecast
端点返回五个天气预报。Enumerable.Range(1, 5)
中的硬编码五可以替换为一个默认 lambda 参数,如下所示更新后的代码片段:
app.MapGet("/weatherforecast", (int days = 5) => {
// 安全检查确保days参数至少为1,不超过50。
var count = days > 0 && Enumerable.Range(1, count).Select(index => new WeatherForecast(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
)).ToArray();
return forecast;
})
这样修改后,MapGet
方法现在接受一个可选的 days
参数,默认值为 5
。虽然默认行为保持不变,但我们向消费者暴露了这个参数。days
参数可以通过查询字符串传递给 API。例如,请求一个 21 天的天气预报的 HTTP 请求如下:
GET /weatherforecast?days=21 HTTP/1.1
Host: localhost:7240
Scheme: https
如果没有从查询字符串中提供 days
参数,就会使用这个默认值。days
参数用于指定应生成多少天的天气预报。
译自:https://devblogs.microsoft.com/dotnet/refactor-your-code-with-default-lambda-parameters/
Comments