跟着杨中科学习(一)Linq和系统配置

.net

Linq

委托->lambda->LINQ

int i=5;

整数类型的变量i指向数据5;

委托是可以指向方法的类型。

调用委托变量时执行的就是变量指向的方法。

.net中定义了泛型委托Action(无返回值)和Func(有返回值),所以一般不用自定义委托类型。

static void f1(int z,int c){

}
//main函数
int main(){
	Action<int,int> f=f1
}

委托变量不仅可以指向普通方法,也可以指向匿名方法。

//delegate开头的为匿名方法的声明
Func<int ,int,string> f1=delegate(int i1,int i2)
{
	return $"{i1}+{i2}={i1+i2}";
};
string s=f1(1,2);

将匿名方法改成lamdba

Func<int ,int,string>=(int i1,int i2)=>{return $"{i1}+{i2}={i1+i2}";};
string s=f1(1,2);

如果 =>之后的方法体中只用一行代码,且方法有返回值,那么可以省略方法体的{}以及return.

Func<int ,int,string> f1=(i1,i2)=>$"{i1}+{i2}={i1+i2}";

LINQ的where方法

int[] nums=new int[]{3,5,6,87,89,45,7,435,45,765,324};
IEnumerable<int> result=num.Where(a=>a>10);
foreach(int i in result)
{
    Console.WriteLine(i);
}

where方法会遍历集合中的每个元素,对每个元素都调用lamdba表达式,判断是否为true.

LINQ常用方法

这些方法中大多都是对基于IENumeable的扩展方法。

//返回符合条件的元素
IEnmerable<int> items=list.where(p=>p.Age>30);
//返回符合条件的元素个数
int item=list.Count(p=>p.Age>30);
//判断是否至少有一条数据符合要求
bool item=list.Any(p=>p.Age>30);

只取其中一条数据

//有且只有一条满足要求的数据,返回数据
Single()
//最多只有一条满足要求的数据,返回数据
SingleOrDefault()
//至少有一条,返回第一条,返回数据
First()
//返回第一条或默认值,返回数据
FirstOrDefault()

排序

//排序
//对数据进行正向排序
//没有无参的构造函数,至少写成OrderBy(i=>i);适用于简单类型
//随机排序OrderBy(e=>Guid.NewGuid());
//支持多条件排序,OrderBy(...).ThenBy(...);
OrderBy()
list.OrderBy(e=>e.Age);
//倒序排序
OrderByDescending()

对于简单类型排序,也许不用lambda表达式。

特殊案例:按照最后一个字符排序;用Guid或者随机书进行随机排序。

跳过

//跳过某些数据,取部分数据
Skip();
Take();
list.Skip(3).Take(2);//跳过二条数据,取第三条数据

聚合函数

Max()//最大值
Min()//最小值
Average()//平均值
Sum()//和
Count()//个数

只要是可以返回IEnmerable的,都可以使用链式调用

分组

IEnumerable<IGrouping<int,Employee>> items=list.GroupBy(e=>e.Age);

映射

把集合中的每一项逐个转换成另一类型

IEnumable<int> age=list.Seleect(e=>e.age);

匿名类型

var obj1=new {Name="ddd",Salary=3,AAA="eadwr",BB=99};
//编译器,定义四个属性,并创建了一个对象

匿名类型和投影结合

var items=list.Select(e=>new {XingMing=e.Name,NianLing=e.Age,XingBie=e.Gender?"男":"女"});

集合转换

我们可以利用ToArray()方法和ToList()分别把IEnumerable转换为数组类型和List类型。

依赖注入

依赖注入是实现控制反转的一种方式

不要在长生命周期的对象内引用短生命周期的对象。

生命周期的选择:

如果类无状态,建议为Singleton;如果类有状态,且有Scope控制,建议为Scoped。使用
瞬态的时候要谨慎。

系统配置

Json文件配置

{
    "name":"yzk",
    "age":"18",
    "proxy":{"address":"aa"}
}

NuGet安装Microsoft.Extensions.Configuration和Mincrosoft.Extensions.Configuration.Json

读取配置原始方法

ConfigurationBuilder configBuilder=new ConfigurationBuilder();
configBuilder.AddJsonFile("config.json",optional:false;reloadOnChange:true);
IConfigurationRoot config=configBuilder.Build();
string name=config["name"];
string proxyAddress=config.GetSection("proxy:address").Value;

optional参数表示这个文件是否可选,设为false文件不存在会报错。

reloadOnChange(可选):一个布尔值,指示是否在文件更改时重新加载配置。如果设置为 true,则当文件更改时,配置将自动重新加载

绑定读取配置

NuGet安装:Microsoft.Extensions.Configuration.Binder

Proxy proxy=configRoot.GetSection("proxy").Get<Proxy>();

把配置文件直接映射为对象也可以

class Config
{
    pubilc string Name{get;set;}
    pubilc int Age{get;set;}
    pubilc Proxy proxy{get;set;}
}
class Proxy
{
    pubilc string Address{get;set;}
}
Config config=configRoot.Get<Config>();
config.Nmae;
config.Proxy.Address;

选择方式读取配置

推荐使用IOptionsSnapshot进行配置的读取,确保一次请求的配置项,不会受到文件修改而修改

Nuget:

Microsoft.Extensions.Options
Microsoft.Extensions.Configuration.Binder
读取配置时,DI要声明IOptions<T>,IOptionsMonitor<T>,IOptionSnapshot<T>
IOptions<T>不会读到最新值,IOptionsMonitor<T>,IOptionSnapshot<T>相比
在一个范围内,读的值不会改变。
    总之使用IOptionSnapshot<T>比较安全,主要使用此就行。

//使用IOptionsSnapshot进行获取配置
class TestController
{
    //Config是一个json类型的配置文件
    private readonly IOptionsSnapshot<Config> optConfig;
    public TextController(IOptionsSnapshot<Config> optConfig)
    {
        this.optConfig=optConfig;
    }
    public void Test()
    {
        Console.WriteLine(optConfig.Value.Age);
    }
}
//使用DI注入功能
    private static void Main(string[] args)
    {
        ServiceCollection services = new ServiceCollection();
        //configRoot绑定到根节点    
        IConfigurationRoot configRoot=configBuilder.Build();
        services.AddOptions().Configure<Config>(e=>configRoot.Bind(e));
        
        service.AddScoped<TestController>();
        // 1.创建服务集合2.向集合中注册服务,3.创建一个服务提供器
        //第一个根对象只能用ServiceLocation的方式进行
        using (var sp = services.BuildServiceProvider())
        {
           var c=sp.GetRequiredService<TestController>();
            c.Test();

        };
        Console.ReadKey();
	}

其他配置提供者

命令行方式配置

使用场景Docker

除了json的文件配置,还有其他类型的文件配置可以使用

Nuget

Microsoft.Extensions.Configuration.CommandLine

//使用DI注入功能
private static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
//configRoot绑定到根节点
services.AddOptions().Configure(e=>configRoot.Bind(e));

    private static void Main(string[] args)
    {
        ServiceCollection services = new ServiceCollection();
       	service.AddScoped<TestController>();
        comfigBuilder.AddCommandLine(args);
        IConfigurationRoot configRoot=configBuilder.Build();
        services.AddOptions().Configure<Config>(e=>configRoot.Bind(e));
        using (var sp = services.BuildServiceProvider())
        {
            var c=sp.GetRequiredService<TestController>();
            c.Test();       
        };
        Console.ReadKey();
	}

扁平化配置

对于复杂结构,要进行扁平化配置

{
    "name":"yzk",
    "age":"18",
    "proxy":{
        "address":"aa",
        "port":"80",
        "ids":[3,5,8]
    }
}

在命令行方式提供参数

name=yzk age=18 proxy:address=aaa proxy:port=80
proxy:ids:0=3 proxy:ids:1=5 proxy:ids:3=8
//使用IOptionsSnapshot进行获取配置
class TestController
{
    //Config是一个json类型的配置文件
    private readonly IOptionsSnapshot<Config> optConfig;
    public TextController(IOptionsSnapshot<Config> optConfig)
    {
        this.optConfig=optConfig;
    }
    public void Test()
    {
        Console.WriteLine(optConfig.Value.Age);
        Console.WriteLine(optConfig.Value.Name);
        Console.WriteLine(optConfig.Value.proxy.Address);
        Console.WriteLine(optConfig.Value.proxy.Port);
        Console.WriteLine(string.Join(",",optConfig.Value.proxy.ids));
        
    }
}

环境变量的配置和命令行方式差不多,都是扁平化配置。

获取环境变量的配置使用

Microsoft.Extensions.Configuration.EnvironmentVariables

获取配置的环境变量

    private static void Main(string[] args)
    {
        ServiceCollection services = new ServiceCollection();
       	service.AddScoped<TestController>();
        //==========================
        //comfigBuilder.AddEnvironmentVariables();
        //还可以允许添加前缀,避免和系统里其他的环境变量冲突
        comfigBuilder.AddEnvironmentVariables("C1_");
        IConfigurationRoot configRoot=configBuilder.Build();
        services.AddOptions().Configure<Config>(e=>configRoot.Bind(e));
        using (var sp = services.BuildServiceProvider())
        {
            var c=sp.GetRequiredService<TestController>();
            c.Test();       
        };
        Console.ReadKey();
	}

其他配置源

还可以使用ini,xml,yaml等格式

中心化配置服务器Apollo,Nacos等开源服务器,或者使用Azure,阿里云等的配置服务。

造轮子 配置的提供者

1、开发一个直接或者间接实现IConfigurationProvider接口的类
XXXConfigurationProvider,一般继承自ConfigurationProvider。
如果是从文件读取,可以继承自FileConfigurationProvider。
重写Load方法,把“扁平化数据”设置到Data属性即可。

2、再开发一个实现了IConfigurationSource接口的类XXXConfigurationSource。
如果是从文件读取,可以继承自FileConfigurationSource。在Build方法中返回
上面的ConfigurationProvider对象。

3、然后使用即可,configurationBuilder.Add(new ConfigurationSource())即可。
为了简化使用,一般提供一个IConfigurationBuilder的扩展方法。

整体流程:编写ConfigurationProvider类实际读取配置;

编写ConfigurationSource在Build中返回ConfigurationProvider对象;

把ConfigurationSource对象加入IConfigurationBuilder。

posted @   想要来杯咖啡吗  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示