July 21st, 2024

C#12新功能合集四:使用默认 lambda 参数重构C#代码

Amy Peng
Partner Tech Advisor

本文翻译于David Pine的这篇文章:Refactor your code with default lambda parameters 。

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

  • 使用默认 lambda 参数重构C#代码(本篇文章)

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

默认 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);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
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) =>
{
    // Safety check to ensure the days parameter is 
    // at least 1, but no more than 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 的详细信息,请参阅可选参数 

下一步计划 

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

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

如果您有任何技术问题,欢迎来Microsoft Q&A 提问。

Author

Amy Peng
Partner Tech Advisor

Amy Peng is a Partner Tech Advisor on the Dev Community Team focused on .NET. Her responsibility is providing technical support on the forum and promote .NET to all the community members.

0 comments