使用默认 lambda 参数重构代码

作者:David Pine

排版:Alan Wang

本文是探讨 C# 12的各种功能的四篇系列文章中的最后一篇。在这篇文章中,我们将探讨“默认 lambda 参数”功能,使开发人员能够在 lambda 表达式中使用默认参数值。本系列涵盖了很多内容:

  1. 使用主构造函数重构 C# 代码

  2. 使用集合表达式重构 C# 代码

  3. 使用任意类型别名重构 C#代码

  4. 使用默认 lambda 参数重构代码(本篇文章)

这些功能是我们不断努力提高代码可读性和可维护性的一部分。让我们详细探索它们!

使用任意类型别名重构 C#代码

https://devblogs.microsoft.com/dotnet/refactor-your-code-using-alias-any-type/

默认 Lambda 参数

默认 lambda 参数是 C# 12 中的一项新功能,允许开发人员在 lambda 中表达默认参数值。此功能是 C# 方法中现有默认参数功能的自然扩展。

C# 12 之前

在 C# 12 之前,当您定义需要提供某种默认行为的 lambda 表达式时,您必须使用空合并运算符 (??) 或条件运算符 (?:)。请查看以下示例:

var IncrementBy = static (int source, int? increment) =>
{
    // Same as 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 表达式中定义 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();


internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

这里有一段来自模板的代码,但它并不是我们真正要关注的重点。我们只需关注 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) 方法调用中的硬编码 5 可以被默认 lambda 参数替换,以下是更新后的代码片段:

app.MapGet("/weatherforecast", (int days = 5) =>
{
    // 安全检查以确保天数参数至少为 1,但不超过 50。
    var count = days is > 0 and <= 50 
        ? days
        : 5;


    var forecast = 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 方法现在接受一个默认值为 5 的可选 days 参数。因此,虽然仍然存在相同的默认行为,但我们向消费者公开了此参数。days 参数可以作为查询字符串传递给 API。例如,以下 HTTP 请求,该请求请求21天的天气预报:

GET /weatherforecast?days=21 HTTP/1.1
Host: localhost:7240
Scheme: https

当查询字符串中未提供 days 参数时,将使用此默认值。days 参数用于指定应生成天气预报的天数。有关 ASP.NET Core Minimal API 的详细信息,请参阅可选参数。

可选参数

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/parameter-binding?view=aspnetcore-8.0#optional-parameters

下一步计划

这就是关于 C# 12 部分新特性系列文章的全部内容了!!我希望您喜欢了解这些新功能以及它们如何帮助您重构代码。

在本文中,您了解了 C# 12 中的默认 lambda 参数功能。此功能允许开发人员在 lambda 中表达默认参数值。请务必在您自己的代码中尝试一下!如需更多资源,我建议您查看以下链接:

  • C# 语言参考:Lambda 表达式

    https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions

  • C# 语言参考:Lambda 方法组默认值

    https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-12.0/lambda-method-group-defaults

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值