C#基础与进阶扩展合集-进阶篇(持续更新)

news2024/11/18 3:41:45

目录

本文分两篇,基础篇点击:C#基础与进阶扩展合集-基础篇

一、进阶

1、Predicate

2、设置C#语言版本

3、ListCollectionView过滤集合

4、值类型与引用类型

5、程序设置当前项目工作目录

6、获取App.config配置文件中的值

7、Linq常用语句

8、并行LINQ

9、强引用与弱引用

10、using处理非托管资源

11、模块初始化器

 二、进阶扩展

 1、Adapt适配器

2、Mutex互斥及防止App多开

3、Monitor设置等待资源时间

4、扩展方法实现解构

5、Span实现切片

6、数组池减少GC工作

7、深度解析await关键字

8、Task常用方法

9、ValueTask

10、异步方法的异常处理

三、版本新增 

1、范围运算符 

2、字符串格式控制 

3、数字分隔符 

4、小数点前后保留格式 


本文分两篇,基础篇点击:C#基础与进阶扩展合集-基础篇

一、进阶

1、Predicate

拥有一个或多个泛型参数并返回一个 bool 值,常用于对 collection 进行一组条件检索,类似于Func。

举例:Predicate pre=m=>m.Id==2;

2、设置C#语言版本

工程文件 x.csproj中修改

PropertyGroup节点内添加子节点:

<LangVersion>latest</LangVersion>

3、ListCollectionView过滤集合

使用ListCollectionView类构造函数注入列表

通过该类的 Filter属性过滤集合

            List<Animal> animals = new List<Animal>() { new Animal(1,"ani1"),new Animal(2,"动物2") };
            List<Bear> bears = new List<Bear>();
            var tmp = animals.Adapt<List<Bear>>();
            tmp.ForEach(m => m.Description = "Animal adapt bear...");
            
            ListCollectionView view=new ListCollectionView(tmp);
            view.Filter = i => ((Bear)i).ID == 2;
            foreach (var animal in view)
                MessageBox.Show(((Bear)animal).Name);

4、值类型与引用类型

值类型:变量直接保存其数据,作为类的字段(成员变量)时,跟随其所属的实例存储,也就是存储在堆中;作为方法中的局部变量时,存储在栈上;

引用类型:变量保存其数据的引用(地址)分配在栈中,具体数据(实例)部署在托管堆中;

值类型:结构体(数值类型,bool型,用户定义的结构体),枚举,可空类型

引用类型:数组,用户定义的类、接口、委托,object,字符串 

引用类型string: 

            string a = "A";
            string b = a;
            Console.WriteLine($"a:{a}\tb:{b}");
            a= "B";
            Console.WriteLine($"a:{a}\tb:{b}");

string为引用类型,上面示例看出string像值类型:

实际上,是由于运算符的重构所导致的结果。当a被重新赋值时,.NET为a在托管堆上重新分配了一块内存。这样做的目的是,使字符串类型与通俗意义上讲的字符串更接地气。

引用类型数组:

数组元素为值类型时,在托管堆中一次性分配全部值类型空间(堆中栈),并自动初始化;

       元素为 引用类型时,先在托管堆分配一次空间,此时不会自动初始化任何元素(均为null)。等到有代码初始化某个元素的时,这个引用类型元素的存储空间才会被分配在托管堆上;

5、程序设置当前项目工作目录

 Directory.SetCurrentDirectory(Path.GetDirectoryName(typeof(Test).Assembly.Location));

6、获取App.config配置文件中的值

1获取appSettings节点值

 ConfigurationManager.AppSettings[key];

2、获取connectionStrings节点值:

var list= ConfigurationManager.ConnectionStrings;

string str="";
foreach (ConnectionStringSettings item in list)

      if(item.Name=="ConTest")
      str = item.ConnectionString;
}

7、Linq常用语句

定义LINQ扩展方法的一个类是System.Linq名称空间中的Enumerable;

Linq常用语句,详细讲解点击:C#-关于LINQ 

select:以指定形式返回

Where查询特点条件(方式1:from in;方式2:Lambda表达式)

Order排序:1、descending 降序;2、ascending 升序

OfType查询特定类型

Join合并两集合通过指定键,返回指定结构类型集合

GroupJoin:俩集合通过指定键分组

Reverse反转集合元素顺序

GroupBy按指定键对自身分组 

Any / All 判断是否(任意一个/全部)满足条件

Skip跳过指定数量元素

 Take拿取指定数量元素

Count获取元素个数

 Sum、Average、Max、Min获取集合总值、平均值、最大值、最小值

Concat连接集合

Distinct去重(去重类中某个字段需实现IEqualityComparer接口

ElementAt获取指定索引元素(与[ ]类似)

First/Single、Last:获取集合中第一个、最后一个元素(如果集合中包含多个元素,使用Single会报错);

ToDictionary:将集合转换为字典;

ToList: 将集合转换为List;

SequenceEqual:判断两个集合是否相等;

8、并行LINQ

System.Linq名称空间中包含的类ParallelEnumerable可将查询的工作拆分到多个处理器上同时运行的多个线程中;

通常可使用AsParallel()方法让集合类以并行方式查询,该方法扩展了IEnumerable<TSource>接口,返回ParallelQuery<TSource>类;

示例如下,示例中并行LINQ所用时间约90ms,普通LINQ所用时间约为420ms,可以看出并行LINQ加快了代码运行速度

var list=Enumerable.Range(0, 5000_0000).Select(x => Random.Shared.Next(100)).ToList();
Stopwatch sw = Stopwatch.StartNew();
var avera= list.AsParallel().Where(m=>m<50).Select(m=>m).Average();
sw.Stop();
Stopwatch sw2 = Stopwatch.StartNew();
var avera2= list.Where(m => m < 50).Select(m => m).Average();
sw2.Stop();
Console.WriteLine(sw.Elapsed.TotalMilliseconds);//约90ms
Console.WriteLine(sw2.Elapsed.TotalMilliseconds);//约420ms

9、强引用与弱引用

1、在应用程序中实例化一个类或结构时,只要有代码引用它,就会形成强引用

2、GC不能收集仍在引用的对象的内存,也就是强引用的内存,但它可以收集不在根表中直接或间接引用的托管内存;

3、弱引用允许创建和使用对象,但如果垃圾收集器碰巧运行,就会收集对象并释放内存,弱引用开销比小对象大,用于小对象没有意义;

4、弱引用使用WeakReference类创建的,使用构造函数传递强引用,其Target属性的值若不为null,则该对象仍可使用,若赋值给传递类型对象,则会再次创建该对象的强引用,不能被GC收集(注意:在访问Target时可能被GC收集,所以通常赋值后需对其进行null判断);

            WeakReference weakReference = new WeakReference(new Pig());
            Pig pig = weakReference.Target as Pig;
            if (pig != null)
            {
                //use pig
            }
            else
            { 
                //reference not available
            }

10、using处理非托管资源

方式一:声明一个析构函数(或终结器finalizer)作为类的成员;

C#中,析构函数在底层.NET体系结构中为终结器,编译器会隐式的把析构函数编译成等价于重写Finalize()方法的代码,如下:

    protected override void Finalize()
    {
        try 
        {
            //Finalizer implementation
        }
        finally 
        {
            base.Finalize();
        }
    }

方式二:实现IDisposable或IAsyncDisposable接口;

C#中,推荐使用该方式替代析构函数,这些接口定义了一种模具(具有语言级的支持),该模式为释放非托管的资源提供了确定的机制,并避免产生析构函数固有的与GC相关的问题;

注意:若处理过程中出现异常则不会释放,通常在finally块中释放,如下:

People people = null;
try
{
    people = new();
    //other process
}
finally
{
    people.Dispose();
}
class People : IDisposable
{
    public void Dispose()
    {
        //implementation
    }
}

 方式三:using语句和using声明(推荐),实现了对方式二的封装;

用于实现IDisposable接口的对象,当对象的引用超出作用域时,自动调用该对象的Dispose()或DisposeAsync()方法,如下示例,会生成与上面try块等价的IL代码;

using (People people = new())
{ 
     //other process
}

11、模块初始化器

若需要在使用一个库的任何类型之前调用该库的初始化代码,可使用C#的一个新特性,模块初始化器[ModuleInitializer]

在使用该类的任何类型之前,会自动调用该特性标记的初始化方法,该方法必须是静态、无参,返回void,使用public或internal访问修饰符;

    [ModuleInitializer]
    public static void Initializer()
    {
        Console.WriteLine("*******Module Initializer********");
    }

 二、进阶扩展

 1、Adapt适配器

安装NutGet包:Mapster

可理解成转换器,适配器适配的是不同类间相同的名称,不论字段或属性(必须为值类型或字符串类型),只要名字相同,都适配给目的对象;

注意:即使名称相同,属性或字段也不能适配成方法

            Animal animal = new Animal(18);
            Bear bear = animal.Adapt<Bear>();
            Console.WriteLine(bear.Age.ToString());
            Console.WriteLine(bear.Description.ToString());
            Console.WriteLine("************************");
            Bear bear1=new Bear();
            Console.WriteLine(bear1.Age.ToString());
            Console.WriteLine(bear1.Description.ToString());
            Console.WriteLine("*************************");
            Banana banana = animal.Adapt(new Banana());
           Console.WriteLine(banana.Description);

2、Mutex互斥及防止App多开

1、继承自WaitHandle类:抽象基类,用于等待一个信号的设置(有静态方法WaitOne()、WaitAll()、WaitAny());

2、Mutex互斥锁可定义互斥名称,所以可用于跨进程的同步操作(因为操作系统可识别有名称的互斥,在不同进程间共享);

3、Mutex构造函数中,可指定互斥是否最初应由主调线程拥有、定义互斥名称、获取互斥是否已存在的信息;

用法1:跨进程互斥实现进程间同步(未命名互斥只能用于跨线程) 

Mutex mutext = new Mutex(false,"MyConsole");
mutext.WaitOne();
Console.WriteLine($"{Process.GetCurrentProcess().ProcessName}:\tStart......");
Console.ReadLine();
mutext.ReleaseMutex();
Console.WriteLine($"{Process.GetCurrentProcess().ProcessName}:\tEnd.......");

 用法2:防止App重复开启

Mutex mutext = new Mutex(false,"MyConsole",out bool createNew);
if (!createNew)
    return;

3、Monitor设置等待资源时间

lock关键字是由Monitor类实现(抛出异常也会解锁)如下:

    Monitor.Enter(_obj);
    try{Count--;}
    finally { Monitor.Exit(_obj); }

Monitor相对于lock的优点在于,使用Monitor的TryEnter()方法,其中可传递一个超时值,用于指定等待被锁定的最长时间,若_obj被锁定,TryEnter()方法将布尔型的引用参数设置为true,并同步的访问_obj锁定状态,若另一个线程锁定_obj时间超过指定时间,TryEnter()将bool引用参数置为false,线程将不再等待,而是去执行其它操作,如下:

    Monitor.TryEnter(_obj, 2000, ref _lockTaken);
    if (_lockTaken)
    {
        try
        {
            Console.WriteLine(Thread.CurrentThread.Name + ":\t obj lock.....");
            Thread.Sleep(5000);
            Console.WriteLine(Thread.CurrentThread.Name + ":\t obj release.....");
        }
        finally
        {
            Monitor.Exit(_obj);
        }
    }
    else
        Console.WriteLine("Timeout,Run other.....");

4、扩展方法实现解构

了解扩展方法点击:扩展方法定义与使用 

创建Deconstruct()方法(也称解构器),将分离部分放入out参数中,这里使用扩展方法实现解构,示例如下:

Stu stu = new Stu(98, "Auston");
stu.Deconstruct(out int score, out string name);
Console.WriteLine($"{name}:{score}");

static class StuExtension
{
    public static void Deconstruct(this Stu stu, out int score, out string name)
    {
        score = stu.Score;
        name = stu.Name;
    }
}

5、Span<T>实现切片

1、Span<T>,可快速访问托管与非托管的连续内存,如数组、长字符串;

2、可实现对数组部分进行访问或切片,不会复制数组元素,是从span中直接访问的,切片的两种方式①构造函数传递数组的开头与结尾;②Slice方法传递开头索引,提取到数组末尾;

3、可使用Span改变值,除了索引访问更改,还提供方法有:Clear()、填充Fill()、复制CopyTo()(不推荐,目标span不够大会抛异常)、复制推荐TryCopyTo()(span不够大不抛异常,而是返回false);

4、若只需对数组片段进行读访问,可使用ReadOnlySpan<T>;

int[] c = { 1, 3, 5, 8 };
Span<int> span = new Span<int>(c);
Span<int> span1= new Span<int>();
span[1] = 11;
span.Clear();
span.Fill(11);
Span<int> span2 = new Span<int>(c,0,3);
Span<int> span3 = span.Slice(0,3);   //切片
ReadOnlySpan<int> span4 = new(c);   //只读变量
if (!span.TryCopyTo(span3))
    Console.WriteLine("Argument");

6、数组池减少GC工作

         通过ArrayPool类(名称空间System.Buffers)使用数组池,可减少垃圾收集器的工作,ArrayPool管理一个数组池,数组可以从这租借,并返回池中,内存在ArrayPool中管理。

创建ArrayPool<T>,调用静态Create()方法;

使用预定义共享池,通过访问Shared属性

从池中租用内存,可调用Rent()方法,(池中数组元素数量最低16,且都是成倍增加);

内存(数组)返回到池中,调用Return()方法,可指定返回池之前是否清除该数组(false,下次租用数组的人可读取数据);

ArrayPool<int> arrayPool = ArrayPool<int>.Create(maxArrayLength: 100, maxArraysPerBucket: 10);
int[] arr = ArrayPool<int>.Shared.Rent(10);
arr[15] = 15;
Console.WriteLine($"Len={arr.Length}\tarr[15]={arr[15]}");//输出Len=16    arr[15]=15
ArrayPool<int>.Shared.Return(arr,true);
Console.WriteLine(arr[15]);//输出0

7、深度解析await关键字

await通常与async一同使用来实现异步编程,async没有await搭配使用将毫无意义;

使用Task任务的GetAwaiter()方法,返回一个TaskAwaiter<T>类型对象,该对象的OnCompleted()方法实现了INotifyCompletion接口,在任务完成时调用;

await实际就是编译器把await关键字后的所有代码放进了OnCompleted()方法的代码块中。

        public static void Main(string[] args)
        {
            TestAsync();
            Console.ReadLine();
        }
        public static async void TestAsync()
        {
            var awaiter = MyAsync().GetAwaiter();
            awaiter.OnCompleted(() =>
            {
                Console.WriteLine($"MyAsync ended....");
            });
            //await MyAsync();
            //Console.WriteLine("MyAsync ended.....");
        }
        public static async Task<string> MyAsync()
        {
            Thread.Sleep(100);
            Console.WriteLine(nameof(MyAsync));
            return nameof(MyAsync);
        }

8、Task常用方法

GetAwaiter()方法,用于await关键字的实现,详细如上;

ContinueWith()方法,用于延续任务;

WhenAll()静态方法,用于等待所有任务结束;

WhenAny()静态方法,用于等待任意一个任务结束;

9、ValueTask

C#7新增可用作await的新类型,ValueTask是一个结构,相对于Task具有性能上的优势,因为其在堆上没有对象;

10、异步方法的异常处理

若调用异步方法没有等待,try/catch不会捕获异常,因为在抛出异常前,就已经执行完毕了,若要捕获异常,需await等待异步方法。

        static void PutError()
        {
            try
            {
               await ThrowExcp();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        static async Task ThrowExcp()
        { 
            await Task.Delay(1000);
            throw new Exception("Exception.....");
        }

19、 

三、版本新增 

C#9新增顶级语句;

字符串的范围除SubString方法,C#8新增hat(^)、范围运算符([..]); 

1、范围运算符 

string rangstr ="hello,auston!" ;
Console.WriteLine(rangstr[..5]);//范围运算符
Console.WriteLine(rangstr[7^2]);//hat^运算符,从索引7往前数第2个字符 

2、字符串格式控制 

 DateTime t = DateTime.Now;
Console.WriteLine($"{t:D}");//字符串格式控制

3、数字分隔符 

 int a = 2_2_2;//使用数字分隔符,提高代码可读性(编译器会忽略下划线)
Console.WriteLine($"{a:c}");

4、小数点前后保留格式 

 double d = 22.336_6;
Console.WriteLine($"{d:###.##}");//小数点后四舍五入保留2位
Console.WriteLine($"{d:000.00}");//小数点前保留3位,后保留2位

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1283492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三种定时器的实现方式

一、Scheduled Schedule是Spring框架提供的一种简单的定时任务调度方法&#xff0c;通过注解的方式即可实现定时任务的调度。它适用于简单的定时任务需求&#xff0c;例如每隔一段时间执行一次任务或者在特定时间执行任务。Scheduled可以轻松地集成到Spring应用中&#xff0c;…

DeepVoice AI - Text To Voice

No sign-up, No API Keys, no recurr

LabVIEW开发工业设备远程在线状态监测

LabVIEW开发工业设备远程在线状态监测 项目需要减少意外停机和维护费用、提供更完整的机器操作和状态图、改进设备使用情况跟踪。 该解决方案是一个多节点&#xff08;即多站点&#xff09;远程监控系统&#xff0c;它利用了基于NI cRIO的控制器和定制的LabVIEW监测软件。 方…

Idea 导入Mysql8.0驱动jar包

库是模块可以依赖的已编译代码的集合。在IntelliJ IDEA中&#xff0c;可以在三个级别上定义库&#xff1a; 全局 &#xff08;可用于许多项目&#xff09;&#xff0c; 项目&#xff08;可用于项目中的所有模块&#xff09;和模块 &#xff08;可用于一个模块&#xff09; 简单…

Leetcode 80 删除排序数组中的重复项 II

class Solution {// 双指针// slow代表已完成需要的数组的后一位&#xff0c;即要插入的位置// fast代表待检查的第一个元素public int removeDuplicates(int[] nums) {return f(nums, 2);}public int f(int[] nums, int k){int n nums.length;int slow k;int fast k;while(…

开源CDN软件GoEdge —— 筑梦之路

官方网站&#xff1a;GoEdge CDN - 制作自己的CDN - GoEdge CDN | 自建CDN GoEdge是一款管理分布式CDN边缘节点的开源工具软件&#xff0c;目的是让用户轻松地、低成本地创建CDN/WAF等应用。 特性 免费 - 开源、免费、自由、开放 简单 - 架构简单清晰&#xff0c;安装简单&a…

vue2使用ElementUI

elementui官网&#xff1a;组件 | Element 1、全部引入 下载&#xff1a;npm i element-ui 在 main.js 中写入以下内容&#xff1a;import Vue from vue; import ElementUI from element-ui; import element-ui/lib/theme-chalk/index.css; import App from ./App.vue;Vue.use(…

12月2号作业

#include <iostream>using namespace std; class Sofa{ private:string setting;string *lying new string;public:Sofa(){cout << "Sofa::无参构造函数" << endl;}Sofa(string setting,string lying):setting(setting),lying(new string (lying)…

封装带插槽的表格

子组件 <template><div><table><thead><tr><th v-for"col,colIndex in columns" :key"colIndex">{{ col.title }}</th></tr></thead><tbody v-if"instList.length >0"><tr …

IDEA 保存自动ESLint格式化

作为后端人员&#xff0c;偶尔修改一下前端代码&#xff0c;ESLint总提示格式不正确。有没有什么办法实现自动格式化呢&#xff1f; 安装插件Save Actions Tool 设置中搜索eslint 勾选 Run eslint --fix on save 这样以后&#xff0c;只要保存文件就会自动格式化了。 参考 …

Python 流程控制

目录 程序流程 顺序结构 分支结构 单分支 双分支 多分支 if 嵌套 循环结构 while循环 for 循环 退出循环 循环与分支嵌套 附录 程序流程 程序是由语句构成&#xff0c;而流程控制语句 是用来控制程序中每条语句执行顺序的语句。可以通过控制语句实现更丰富的逻辑…

vue+electron问题汇总

1. Vue_Bug Failed to fetch extension, trying 4 more times 描述&#xff1a;项目启动时报错 解决&#xff1a;注释图片中内容 2. Module not found: Error: Can’t resolve ‘fs’ in 描述&#xff1a;项目启动报错 解决&#xff1a;vue.config.js中添加图中数据 3.导入…

开会做笔记的时候用什么软件比较好?

在工作生涯中&#xff0c;会经历很多大大小小的会议&#xff0c;而如何快速准确记录下会议上重要的内容&#xff0c;成了很多上班族的必修课。在会上做笔记&#xff0c;选择什么样的工具才能事半功倍&#xff0c;成了一个值得深思的问题。而经过一段时间的测评后&#xff0c;我…

Windows系统下配置多个版本的jdk

1:准备多个版本的jdk 下载地址:Java Downloads | Oracle 2:安装多个版本的jdk 3:跳转到环境变量配置页 主要是配置环境变量,win10系统操作如下 1)搜索控制面板 2)点击系统与安全 3)点击系统 4)点击高级系统设置 5)点击环境变量 4:为多个版本的jdk配置环境变量 将多个版本的jd…

深度学习(五):pytorch迁移学习之resnet50

1.迁移学习 迁移学习是一种机器学习方法&#xff0c;它通过将已经在一个任务上学习到的知识应用到另一个相关任务上&#xff0c;来改善模型的性能。迁移学习可以解决数据不足或标注困难的问题&#xff0c;同时可以加快模型的训练速度。 迁移学习的核心思想是将源领域的知识迁…

专业做除甲醛净化器的品牌 甲醛净化器什么牌子最好用

室内产生了超标的甲醛&#xff0c;大部分都会采取选择甲醛空气净化器来去除&#xff0c;甲醛净化器逐渐成为室内清除甲醛的主力&#xff0c;在选择甲醛净化器时&#xff0c;人们常常会被市场上琳琅满目的空气净化器品牌所迷惑&#xff0c;各品牌和型号都声称自己最好&#xff0…

关于 Windows 11 显示更多选项

更新 Windows 11 后&#xff0c;右键鼠标出现 显示更多选项&#xff0c;本文解决如何默认显示所有选项 默认显示更多选项 winR打开运行框输入cmd回车输入下面的命令并回车&#xff0c;重启系统 reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c9…

10、SQL注入——数据库基础

文章目录 一、数据库概述二、数据库分类Mysql数据库连接方法 三、识别数据库四、SQL语法4.1 SQL基本语法4.2 高级操作 一、数据库概述 数据库&#xff08;database&#xff09;&#xff1a;存储在磁盘、磁带、光盘或其他外存介质上、按一定结构组织在一起的相关数据的集合。数…

Linux常用命令——atq命令

在线Linux命令查询工具 atq 列出当前用户的at任务列表 补充说明 atq命令显示系统中待执行的任务列表&#xff0c;也就是列出当前用户的at任务列表。 语法 atq(选项)选项 -V&#xff1a;显示版本号&#xff1b; -q&#xff1a;查询指定队列的任务。实例 at now 10 minu…

Figma安装指南:新手入门必看!

如果您想下载Figma客户端&#xff0c;可以直接在Figma官网Products>Downloads页面下载。 如果你不能访问Figma的官方网站&#xff0c;即使下载到客户端&#xff0c;你的网络环境也不能正常使用。 因为Figma的服务器在国外&#xff0c;在国内访问时经常会遇到网络不稳定的情…