当前位置: 首页 > news >正文

利用接口中的静态虚拟成员实现自定义配置节

利用接口中的静态虚拟成员实现自定义配置节

C# 11引入了一项新特性——接口中的静态虚拟成员。该特性的主要动机是支持通用数学算法。提到数学可能会让一些人忽略这个特性,但实际上它在其他场景中也很有用。

例如,我利用这个特性清理了注册和使用自定义配置节类型的方式。

自定义配置节

作为回顾,让我们看看自定义配置节。假设您想在appSettings.json中配置API客户端。您可以将配置节映射到类型。例如,以下是我某个项目中的appSettings.json文件。

{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": "*","OpenAI": {"ApiKey": "Set this in User Secrets","OrganizationId": "{Set this to your org id}","Model": "gpt-4","EmbeddingModel": "text-embedding-3-large"}
}

与其通过IConfiguration API逐个读取"OpenAI"设置,我更倾向于将其映射到一个类型。

public class OpenAIOptions {public string? ApiKey { get; init; }public string? OrganizationId { get; init; }public string Model { get; init; } = "gpt-3.5-turbo";public string EmbeddingModel { get; init; } = "text-embedding-ada-002";
}

在Program.cs中,我可以配置这个映射。

builder.Configuration.Configure<OpenAIOptions>(builder.Configuration.GetSection("OpenAI"));

配置完成后,我可以将IOptions注入到通过依赖解析解析的任何类中,并以强类型方式访问配置节属性。

using Microsoft.Extensions.Options;public class OpenAIClient(IOptions<OpenAIOptions> options) {string? ApiKey => options.Value.ApiKey;string? Model => options.Value.Model;// ...
}

有时,由于某种原因无法注入IOptions。您可以通过IConfiguration获取它。

Configuration.GetSection("OpenAI").Get<OpenAIOptions>()

静态虚拟接口来清理

这一切都很好,但当您有多个配置类时,会有些重复。我希望构建一个更基于约定的方法。这就是静态虚拟成员接口派上用场的地方。

首先,为所有配置节定义一个接口。

public interface IConfigOptions
{static abstract string SectionName { get; }
}

注意,有一个名为SectionName的静态抽象字符串属性。这是静态虚拟成员。任何实现此接口的类型都必须实现静态SectionName属性。

现在,我将在配置类中实现该接口。

public class OpenAIOptions : IConfigOptions {public static string SectionName => "OpenAI";public string? ApiKey { get; init; }public string? OrganizationId { get; init; }public string Model { get; init; } = "gpt-3.5-turbo";public string EmbeddingModel { get; init; } = "text-embedding-ada-002";
}

有了这个,我可以实现一个扩展方法来在注册配置节类型时访问SectionName。

public static class OptionsExtensions {public static IHostApplicationBuilder Configure<TOptions>(this IHostApplicationBuilder builder)where TOptions : class, IConfigOptions{var section = builder.Configuration.GetSection(TOptions.SectionName);builder.Services.Configure<TOptions>(section);return builder;}public static TOptions? GetConfigurationSection<TOptions>(this IHostApplicationBuilder builder)where TOptions : class, IConfigOptions{return builder.Configuration.GetSection(TOptions.SectionName).Get<TOptions>();}
}

现在,使用这个方法,我可以这样注册配置节:

builder.Configure<OpenAIOptions>();

当您有多个配置节需要配置时,注册代码看起来简洁明了。

例如,在一个项目中,我有这样的部分:

builder.Configure<OpenAIOptions>().Configure<GitHubOptions>().Configure<GoogleOptions>().Configure<WeatherOptions>()

结论

敏锐的读者会注意到,我不需要在这里使用静态虚拟成员。我本可以通过使用反射从类型名称中提取配置节名称来构建基于约定的方法。确实如此,但代码不如这种方法紧凑。此外,有时您可能希望类型名称与节名称不同。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)

公众号二维码

公众号二维码

http://www.hskmm.com/?act=detail&tid=21725

相关文章:

  • 天线增益与有源接收面积之间的关系
  • 2025CSP-S晋级和英才计划入围后:我走过了哪些路
  • 流量分析
  • fdsaf -
  • 【J+S 二十连测】-- 第十二套爆炸记
  • 2025-2026-1 CS3311 软件工程 个人项目第一版已发布
  • Python浅拷贝、深拷贝
  • 破解 Pycharm
  • 阿里业务身份建模
  • 实用指南:矩阵结构体 图片绘制 超级玛丽demo6
  • 5分钟理清:Session、JWT、Token、SSO、OAuth 2.0 认证逻辑
  • 2025年10.1~10.6日信息竞赛计划安排表
  • 【Rust GUI开发入门】编写一个本地音乐播放器(10. 拼装UI组件) - Jordan
  • 国产数据库-达梦docker镜像安装
  • CAP 8.4 版本发布通告
  • 【Leetcode】随笔 - 详解
  • DevEco Studio 编辑器的使用 - 实践
  • docker安装MySQL8.0.25的坑
  • WPF 深入系列.2.布局系统.尺寸属性 - 指南
  • 实训
  • Kosaraju算法
  • bat批处理设置临时PATH路径不能访问
  • 10. Spring AI + RAG - Rainbow
  • 《AI智能体实战研发教程(从0到企业级项目落地)》全网上线|CSDN B站同步首发
  • 9. Spring AI 当中对应 MCP 的操作 - Rainbow
  • 9/30
  • rhel8无法输入中文问题(红帽8安装中文输入法)
  • 威佐夫博弈(Wythoff‘s Game)
  • C语言⽂件管理讲解(1)
  • 2025年9月30日