0%

深入理解单例模式 - 创建型模式的精髓

单例模式是一种创建型设计模式,其目的是确保一个类只有一个实例,并提供全局访问点。在许多场景中,单例模式被用于管理全局状态、资源共享以及限制对象的创建。在本文中,我们将深入探讨单例模式的概念、实现方式以及在实际应用中的使用场景。

单例模式的概念

单例模式是设计模式中最简单但也是最常用的模式之一。其核心思想是通过限制一个类只能有一个实例,确保该实例能够被全局访问。这通常通过以下几个要素来实现:

  1. 私有构造函数: 防止外部通过构造函数创建实例。
  2. 私有静态变量: 用于保存实例。
  3. 公有静态方法(全局访问点): 用于获取实例。

单例模式的实现方式

在C#中,实现单例模式的方式有多种,以下是其中两种常见的实现方式:

1. 懒汉式单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// <summary>
/// 懒汉式单例类
/// </summary>
class Singleton
{
private static Singleton instance;
private static readonly object syncRoot = new object();
public static Singleton GetInstance()
{
//双重锁定
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}

这种实现方式在需要时才创建实例,称为懒汉式。通过 lock 语句确保多线程环境下的安全创建。

2. 饿汉式单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
/// 懒汉式单例类
/// </summary>
class Singleton
{
private static Singleton instance;
private static readonly object syncRoot = new object();
public static Singleton GetInstance()
{
//双重锁定
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}

这种实现方式在类加载时就创建实例,称为饿汉式。由于在类加载时就创建,因此不存在多线程安全问题。

单例模式的应用场景

单例模式适用于以下场景:

  1. 资源共享: 当应用中需要共享资源(如配置信息、日志对象)时,单例模式能够确保只有一个实例处理这些共享资源。

  2. 全局状态管理: 当某个对象需要在系统中保存全局状态时,单例模式能够提供一个统一的入口点来管理这个状态。

  3. 唯一访问点: 当某个类的实例只能有一个访问点时,如工厂类、线程池等,单例模式能够确保只有一个实例提供访问点。

单例模式的注意事项

  1. 多线程安全: 在多线程环境下,懒汉式单例模式需要考虑线程安全问题,可通过 lockdouble-check 等方式解决。

  2. 延迟加载: 懒汉式单例模式支持延迟加载,但在需要时创建实例,可能会引入性能开销。

  3. 反序列化安全: 如果单例类可能被序列化和反序列化,需要实现 ISerializable 接口并提供 OnDeserialized 方法,以确保反序列化后仍然是单例。

总结

使用Singleton 模式的意图就是要保证一个类只有一个实例,同时提供客户程序一个访问它的全局访问点。虽然经典Singleton 模式旨在控制实例的数量,但受到种种“隐性”破坏因素的威胁,我们还需要实施各种针对性的实例数量控制手段。

单例模式是一种简单而强大的设计模式,适用于多种场景。通过合理选择懒汉式或饿汉式的实现方式,可以满足不同的需求。在实际应用中,合理使用单例模式能够提高代码的可维护性和整体设计的灵活性。

创建者模式 - 创建型模式的优雅构建者

在软件设计中,创建者模式是一种创建型设计模式,旨在通过将一个复杂对象的构建过程与其表示分离,从而使同样的构建过程可以创建不同的表示。本文将深入讨论创建者模式的概念、实现方式以及在实际应用中的使用场景。

创建者模式的概念

创建者模式(Builder Pattern)是一种对象创建型设计模式,它提供了一种分步构建复杂对象的方法,使得同样的构建过程可以创建不同的表示。通过将一个大的构建过程分解为多个小的构建步骤,可以更灵活地创建对象。

创建者模式的实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System;
using System.Collections.Generic;

// 产品类
public class Product
{
private List<string> parts = new List<string>();

public void AddPart(string part)
{
parts.Add(part);
}

public void Show()
{
Console.WriteLine("Product Parts:");
foreach (var part in parts)
{
Console.WriteLine(part);
}
}
}

// 抽象构建者接口
public interface IBuilder
{
void BuildPartA();
void BuildPartB();
Product GetResult();
}

// 具体构建者
public class ConcreteBuilder : IBuilder
{
private Product product = new Product();

public void BuildPartA()
{
product.AddPart("Part A");
}

public void BuildPartB()
{
product.AddPart("Part B");
}

public Product GetResult()
{
return product;
}
}

// 指导者
public class Director
{
private IBuilder builder;

public Director(IBuilder builder)
{
this.builder = builder;
}

public void Construct()
{
builder.BuildPartA();
builder.BuildPartB();
}
}

创建者模式的应用场景

创建者模式适用于以下情况:

  1. 当一个对象有复杂的内部结构(多个部分)时。
  2. 当构建过程必须独立于创建具体对象的表示时。
  3. 当同样的构建过程需要创建不同的表示时。

创建者模式的优势

  1. 分步构建: 将构建过程分解为多个步骤,使得对象的构建更加灵活,可以根据需要选择性地执行构建步骤。

  2. 独立构建过程和表示: 构建者模式将构建过程和表示分离,使得同样的构建过程可以创建不同的表示,客户端无需关心对象的具体构建过程。

  3. 更好的封装性: 客户端只需要知道 Director 和 IBuilder 接口,无需关心具体的构建者和产品实现,从而更好地封装了对象的创建过程。

总结

创建者模式可以将一个产品的内部表象与产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。根据上下文需要,我们除了要设计具有装配能力的创建者,必要的时候还要能够有序拆解目标实例。

创建者模式是一种非常有用的创建型设计模式,它通过将复杂对象的构建过程分解为多个小的构建步骤,提供了一种优雅的构建对象的方式。在实际应用中,当对象具有复杂的内部结构、需要独立构建过程和表示、或者构建过程需要灵活性时,创建者模式是一个很好的选择。

深入探讨抽象工厂模式 - 创建型模式的灵活工厂设计

在软件设计中,抽象工厂模式是一种创建型设计模式,旨在提供一个接口用于创建相关或依赖对象的家族,而不需要明确指定它们的具体类。本文将深入探讨抽象工厂模式的概念、实现方式以及在实际应用中的使用场景。

抽象工厂模式的概念

抽象工厂模式是一种创建型设计模式,它提供一个接口,用于创建一系列相关或依赖对象的家族,而无需指定它们的具体类。抽象工厂允许客户端代码使用抽象接口来创建一组相关的产品,而不必关心这些产品的具体实现。

抽象工厂模式的实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/// <summary>
/// 提供一个创建一系列相关或依赖对象的的接口
/// 而无需指定它们具体的类
/// </summary>
public class 抽象工厂模式
{
[Fact]
public void Test()
{
User user = new User();

IFactory factory = new SqlserverFactory();
IUser iu = factory.CreateUser();

iu.Insert(user);
iu.GetUser(1);
}
/// <summary>
/// 定义一个创建访问User表对象的抽象的工厂接口
/// </summary>
interface IFactory
{
IUser CreateUser();
}
/// <summary>
/// 实例化SqlserverUser
/// </summary>
class SqlserverFactory : IFactory
{
public IUser CreateUser()
{
return new SqlserverUser();
}
}
/// <summary>
/// 实例化AccessUser
/// </summary>
class AccessFactory : IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
}
/// <summary>
/// 用户客户端访问,解除与具体数据库访问的耦合
/// </summary>
interface IUser
{
void Insert(User user);
User GetUser(int id);
}
/// <summary>
/// sqlserver具体类
/// </summary>
class SqlserverUser : IUser
{
public void Insert(User user)
{
Console.WriteLine("sqlserver 新增一条数据");
}

public User GetUser(int id)
{
Console.WriteLine("sqlserver 获取一条数据");
return null;
}
}
/// <summary>
/// Access具体类
/// </summary>
class AccessUser : IUser
{
public User GetUser(int id)
{
Console.WriteLine("Access 获取一条数据");
return null;
}

public void Insert(User user)
{
Console.WriteLine("Access 新增一条数据");
}
}

class User
{
public int Id { get; set; }
public string Name { get; set; }
}
}

抽象工厂模式的应用场景

抽象工厂模式适用于以下情况:

  1. 系统需要独立于它的产品的创建、组合和表示时。
  2. 系统要配置多个产品族中的一个,以适应特定的上下文需求。
  3. 强调一系列相关的产品对象的设计以便进行联合使用时。
  4. 提供一个产品类库,而只想显示它的接口而不是实现时。

总结

提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类型。借助类型映射器、配置、委托等手段都可以进一步扩展抽象工厂构造“一组相关或相互依赖对象接口”的能力。

抽象工厂模式是一种强大的设计模式,它提供了一种创建相关或依赖对象家族的方式,使得系统更具灵活性和可扩展性。通过使用抽象工厂模式,可以隐藏具体产品的实现细节,使得客户端代码更加独立于具体产品的变化。在设计中,选择合适的设计模式取决于问题的复杂性和需求的变化性,抽象工厂模式是一个很好的选择。

设计模式的来源:

设计模式是前人的开发总结,可以解决复杂的代码架构问题,可以使用各种开发套路解决开发过程中出现的各种问题。灵活的使用设计模式可以提高代码的质量,让代码的复用性、可维护性、可读性、稳健性以及安全性得到很高提升的解决方案

设计模式从1905年就已经被GOF(四人组)提出,并且记录到了《设计模式:可复用面向对象软件的基础》这本书里面。书中共记录了23种设计模式,这对于设计模式的发展有里程碑的意义,这23种设计模式也被为称为《GOF设计模式》

随着很多年的发展,网络上面的设计模式资料没有发生很大的变化,还是这23种模式,但是大多的资料是java语言版本的,但是在c#语言方面,为了方便开发者使用设计模式,在dotnet框架的设计方案中已经在平台层面添加了很多的设计模式内容。
我们后面围绕这设计模式的场景和具体方案,来具体了解一下设计模式的魅力吧。

设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。这些模式解决了特定问题,让开发人员能够更有效地进行软件开发。设计模式通常可以分为三大类:

1. 创建型模式(Creational Patterns):

这些模式关注对象的创建机制,试图以适合的方式创建对象。它们主要包括:

  • 工厂方法模式(Factory Method Pattern): 定义一个用于创建对象的接口,让子类决定实例化哪个类。

  • 抽象工厂模式(Abstract Factory Pattern): 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

  • 建造者模式(Builder Pattern): 将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

  • 原型模式(Prototype Pattern): 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

  • 单例模式(Singleton Pattern): 保证一个类只有一个实例,并提供一个全局访问点。

2. 结构型模式(Structural Patterns):

这些模式关注类和对象的组合,用于形成更大的结构。它们主要包括:

  • 适配器模式(Adapter Pattern): 将一个类的接口转换成客户希望的另外一个接口。

  • 桥接模式(Bridge Pattern): 将抽象部分与实现部分分离,使它们可以独立变化。

  • 组合模式(Composite Pattern): 将对象组合成树形结构以表示”部分-整体”的层次结构。

  • 装饰者模式(Decorator Pattern): 动态地给对象添加一些额外的职责。

  • 外观模式(Facade Pattern): 为子系统中的一组接口提供一个一致的界面。

  • 享元模式(Flyweight Pattern): 通过共享技术来有效地支持大量细粒度的对象。

  • 代理模式(Proxy Pattern): 为其他对象提供一种代理以控制对这个对象的访问。

3. 行为型模式(Behavioral Patterns):

这些模式关注对象之间的通信,以及算法的责任分配。它们主要包括:

  • 责任链模式(Chain of Responsibility Pattern): 使多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合。

  • 命令模式(Command Pattern): 将一个请求封装成一个对象,从而使用户可以用不同的请求对客户进行参数化。

  • 解释器模式(Interpreter Pattern): 定义语言的文法,并且建立一个解释器来解释该语言中的句子。

  • 迭代器模式(Iterator Pattern): 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露其内部的表示。

  • 中介者模式(Mediator Pattern): 用一个中介对象来封装一系列的对象交互。

  • 备忘录模式(Memento Pattern): 在不破坏封装性的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。

  • 观察者模式(Observer Pattern): 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

  • 状态模式(State Pattern): 允许一个对象在其内部状态改变时改变它的行为。

  • 策略模式(Strategy Pattern): 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。

  • 模板方法模式(Template Method Pattern): 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

  • 访问者模式(Visitor Pattern): 表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

这些设计模式在不同的情境下解决了软件开发中的各种问题,开发人员可以根据实际需求选择合适的设计模式来提高代码的可维护性、可扩展性和重用性。

1.0 2002 年 1 月 Visual Studio .NET 2002

目标是一个简单、现代、通用的面向对象语言,c#刚推出的时候,还没有现在常用的泛型、linq,c#早期和java代码格式非常像,在windows平台上,c#1.0是java的一个可行的替代之选

C# 1.0 的主要功能包括:

  • 结构
  • 接口
  • 事件
  • 属性
  • 委托
  • 运算符和表达式
  • 语句
  • 特性

1.2 2003 年 4 月 Visual Studio .NET 2003

添加了一个小改动 在foreach循环的时候会对  IEnumerator  的 IDisposable实现调用 Dispose

2.0 2005年11月 Visual Studio 2005

新加的功能:

  • 泛型
  • 分部类型
  • 匿名方法
  • 可以为 null 的值类型
  • 迭代器
  • 协变和逆变
    还有其它的更新:
  • getter/setter 单独可访问性
  • 方法组转换(委托)
  • 静态类
  • 委托推断

重点说明:

泛型:在c#2.0 开始支持了 泛型 (通过泛型,类型和方法可以操作任意类型,同时保持类型的安全性。如 List,获得List、List并且可以对这些字符串或整数执行类型安全操作,现时进行循环访问。在泛型出现之前,想达到相同的效果 需要派生自 ArrayList、ListInt类型,还需要进行操作Object强制转换,明显使用泛型更方便高效)
迭代器:迭代器允许使用foreach检查 可枚举类 如List的所有项。 迭代器可以提升语言的可读性
此时java已经发布了包含了泛型和迭代器的版本,c#在追赶java
元组返回内容在DOTNET异常处理的优化
将错误异常对象返回到元组参数,判断异常对象是否为null,
tps可以从900提升到3k

3.0 2007年 11月  Visual Studio 2008

新增的功能:

  • 自动实现的属性
  • 匿名类型
  • 查询表达式
  • Lambda 表达式
  • 表达式树
  • 扩展方法
  • 隐式类型本地变量
  • 分部方法
  • 对象和集合初始值设定项

重点说明:
构造linq的时候可以通过 表达式数、Lambda表达式、匿名类型 实现。这些概念让c#不只是一种面向对象的语言,也可以进行函数式变成,成为了一种混合语言。如计算总合不需要使用for求和,可以通过List.Sum()方法。查询表达式和扩展方法让编程更方便了。

4.0 2010年4月 Visual Studio 2010

新增的功能;

  • 动态绑定
  • 命名参数/可选参数
  • 泛型协变和逆变
  • 嵌入的互操作类型
    重点说明:
    dynamic关键字可以创建和动态类型语言(如js)类似的构造,c#提供了强大的动态类型的语言功能。(个人不建议在dotnet大范围使用dynamic,会有类型相关出错的可能性)
    泛型协变和遡变在框架和库的开发者使用的较多。

5.0 2012年8月  Visual Studio 2012

新增的功能:

  • 异步成员
  • 调用方信息特性
  • 代码工程:C# 5.0 中的调用方信息属性

重点说明:
async await 是 这个版本的主角,在语言层面引入异步操作的关键字,异步代码非常简单实现
调用方信息特性让你可以轻松检索上下文的信息,不需要采用大量样本反射代码。 这在诊断和日志记录任务中也很有用。
6.0 2015年 7月 Visual Studio 2015
新增的功能

  • 静态导入
  • 异常筛选器
  • 自动属性初始化表达式
  • Expression bodied 成员
  • Null 传播器
  • 字符串内插
  • nameof 运算符
    其他新功能包括:
  • 索引初始化表达式
  • Catch/Finally 块中的 Await
  • 仅限 getter 属性的默认值

    重点说明:

语言层面没有太大的功能添加,但是 c#编译器使用c#编写了。Roslyn 重要的特性就是Compiler as a Service 简单的讲,就是就是将编译器开放为一种可在代码中调用的服务,

7.0 2017年3月 Visual Studio 2017

新增功能:

  • out 变量
  • 元组和析构函数
  • 模式匹配
  • 本地函数
  • 已扩展 expression bodied 成员
  • ref 局部变量
  • 引用返回

其他功能包括:

  • 弃元
  • 二进制文本和数字分隔符
  • 引发表达式

重点说明:
重点是使代码变得更简洁,此时的dotnet在dotnetcore 的云平台和可移植性发力。
7.1 2017年8月 Visual Studio 2017

此版本中新增的语言功能包括:

  • asyncMain 方法
  • 应用程序的入口点可以含有 async 修饰符
  • default 文本表达式
  • 在可以推断目标类型的情况下,可在默认值表达式中使用默认文本表达式。 让代码简洁优雅
  • 推断元组元素名称
  • 在许多情况下,可通过元组初始化来推断元组元素的名称。
  • 泛型类型参数的模式匹配
  • 可以对类型为泛型类型参数的变量使用模式匹配表达式。
    编译器有 -refout 和 -refonly 两个选项,可用于控制引用程序集生成

7.2 2017年11月 Visual Studio 2017

C# 7.2 版添加了几个小型语言功能:

  • stackalloc 
  • 对支持模式的任何类型使用 fixed 
  • 无需固定即可访问固定的字段。
  • 重新分配 ref 
  • 声明 readonly struct  in 
  • 在实参上添加 in 
  • 对方法返回项使用  ref readonly 
  • 声明  ref struct 
  • 使用其他泛型约束。
  • 非尾随命名参数
  • 命名的参数可后接位置参数。
  • 数值文字中的前导下划线
  • 数值文字现可在任何打印数字前放置前导下划线。
  • private protected 访问修饰符
  • private protected 
  • 条件 ref
  • 现在可以引用条件表达式 ?:的结果

7.3 2018年5月

C# 7.3 版本有两个主要主题。 第一个主题提供使安全代码的性能与不安全代码的性能一样好的功能。 第二个主题提供对现有功能的增量改进。 此外,此版本中还添加了新的编译器选项。

8.0 2019年9月

C# 8.0 版是专门面向 .NET C# Core 的第一个主要 C# 版本。 一些功能依赖于新的 CLR 功能,而其他功能依赖于仅在 .NET Core 中添加的库类型。 

C# 8.0 向 C# 语言添加了以下功能和增强功能:

  • Readonly 成员
  • 默认接口方法
  • 模式匹配增强功能
  • switch 表达式
  • 属性模式
  • 元组模式
  • 位置模式
  • Using 声明
  • 静态本地函数
  • 可处置的 ref 结构
  • 可为空引用类型
  • 异步流
  • 索引和范围
  • Null 合并赋值
  • 非托管构造类型
  • 嵌套表达式中的 Stackalloc
  • 内插逐字字符串的增强功能

9.0 2020年11月

C# 9 随 .NET 5 一起发布。 它是面向 .NET 5 版本的任何程序集的默认语言版本。 它包含以下新功能和增强功能:

  • 记录
  • 仅限 Init 的资源库
  • 顶级语句
  • 模式匹配增强功能
  • 性能和互操作性
  • 本机大小的整数
  • 函数指针
  • 禁止发出 localsinit 标志
  • 调整和完成功能
  • 目标类型的 new 表达式
  • static 匿名函数
  • 目标类型的条件表达式
  • 协变返回类型
  • 扩展 GetEnumerator 支持 foreach 循环
  • Lambda 弃元参数
  • 本地函数的属性
  • 支持代码生成器
  • 模块初始值设定项
  • 分部方法的新功能

主要内容:

  1. 删除不必要的模式:顶级语句意味着主程序将更易于读取。 减少了不必要的模式:命名空间、Program 类和 static void Main() 都是不必要的。
  2. 将数据与算法分离:records 的引入为遵循值语义的引用类型提供了简洁的语法,以实现相等性。 你将使用这些类型来定义通常定义最小行为的数据容器。 仅限 Init 的资源库在记录中提供了非破坏性修改功能(with 表达式)。 C# 9 还添加了协变返回类型,以便派生记录可以重写虚拟方法,并返回从基方法的返回类型派生的类型。
  3. 更多位置提供更多模式:模式匹配功能以多种方式进行了扩展。 数值类型现在支持范围模式。 可以使用and、or 和not 模式组合模式。 可以通过添加括号来阐明更复杂的模式。
  4. 高性能计算相关(不安全的代码,个人不建议使用):
  • nint 和 nuint 类型对目标cpu的本机大小整数类型进行建模 
  • 函数指针 提供类似委托功能,同时避免创建委托对象所需的分配
  • localsinit  指令可以省略以保存指令

另一组改进支持代码生成器添加功能的场景

  • 模块初始化表达式 是程序集加载时运行时调用的方法
  • 分部方法 支持新的可访问修饰符和非 void 返回类型。 在这些情况下,必须提供一个实现。

小功能,提高了开发人员的工作效率,包括编写和读取代码:

  • 目标类型  new 表达式
  • static 匿名函数
  • 目标类型的条件表达式
  • 扩展 GetEnumerator()  支持 foreach 循环 
  • Lambda 表达式可以声明弃元参数
  • 特性可应用于本地函数

C# 9 版本继续致力于让 C# 成为一种新式通用编程语言。 功能继续支持新式工作负载和应用程序类型。

10 2021年11月

C# 10 继续致力于删除不必要的模式、将数据与算法分离以及提高 .NET 运行时的性能等主题。

C# 10 向 C# 语言添加了以下功能和增强功能:

  • 记录结构
  • 结构类型的改进
  • 内插字符串处理程序
  • global using 指令
  • 文件范围的命名空间声明
  • 扩展属性模式
  • 对 Lambda 表达式的改进
  • 可使用 const 内插字符串
  • 记录类型可密封 ToString()
  • 改进型明确赋值
  • 在同一析构中可同时进行赋值和声明
  • 可在方法上使用 AsyncMethodBuilder 属性
  • CallerArgumentExpression 属性
  • 增强的 #line pragma

11 2023年11月

  1. C# 11 引入了泛型数学以及支持该目标的几个功能。 可以为所有数字类型编写一次数值算法。
  2. 简化 struct 类型处理,例如所需成员和自动默认结构
  3. 使用原始字符串文本、字符串内插中的换行符和 UTF-8 字符串文本可以更轻松地处理字符串。
  4. 文件本地类型等功能使源生成器更简单。
  5. 最后,列表模式添加了对模式匹配的更多支持。

C# 11 中增加了以下功能:

  • 原始字符串字面量
  • 泛型数学支持
  • 泛型属性
  • UTF-8 字符串字面量
  • 字符串内插表达式中的换行符
  • 列表模式
  • 文件本地类型
  • 必需的成员
  • 自动默认结构
  • 常量 string 上的模式匹配 Span
  • 扩展的 nameof 范围
  • 数值 IntPtr
  • ref 字段和 scoped ref
  • 改进了方法组向委托的转换
  • 警告波 7

内容参考:

https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-version-history

为简单起见,通常建议使用 wsl --install 安装适用于 Linux 的 Windows 子系统,但如果运行的是旧版 Windows,则可能不支持这种方式。 下面介绍了手动安装步骤。

阅读全文 »

ElasticSearch是一个高度可扩展的开源搜索引擎并使用REST API,它可以快速地储存、搜索和分析海量数据。维基百科、Stack Overflow、Github 都采用它。层是开源库 Lucene。但是,你没法直接用 Lucene,必须自己写代码去调用它的接口。elasticsearch 是 Lucene 的封装,提供了 REST API 的操作接口,开箱即用。

阅读全文 »