Skip to content

Commit dd5186a

Browse files
committed
episode 35
1 parent 789fa19 commit dd5186a

File tree

13 files changed

+258
-2
lines changed

13 files changed

+258
-2
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
### 2023
1818

19-
**三月份**[第 034 期](docs/episode-034.md) :high_brightness: | [第 033 期](docs/episode-033.md)
19+
**五月份**[第 035 期](docs/episode-035.md) :high_brightness:
20+
21+
**三月份**[第 034 期](docs/episode-034.md) | [第 033 期](docs/episode-033.md)
2022

2123
**二月份**[第 032 期](docs/episode-032.md)
2224

docs/episode-034.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## 卷首语
44

5-
上周有人朋友问了一个问题,怎么实现在多线程中使用 `Dictionary`, 最直接想法是使用 `ConcurrentDictionary` 类型。但是这个类太重了, 因为在性能重要的应用场景中,并不是一个很好的选择。如果直接使用 `lock` 方法,又太简单粗暴,因为更多使用场景是多线程读,而不是写。后来就问了一下 `ChatGPT`,看到它又什么建议:
5+
上周有个朋友问了一个问题,怎么实现在多线程中使用 `Dictionary`, 最直接想法是使用 `ConcurrentDictionary` 类型。但是这个类太重了, 因为在性能重要的应用场景中,并不是一个很好的选择。如果直接使用 `lock` 方法,又太简单粗暴,因为更多使用场景是多线程读,而不是写。后来就问了一下 `ChatGPT`,看到它又什么建议:
66

77
Q: How to use the C# dictionary in in multiple threads?
88

docs/episode-035.md

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
# .NET 每周分享第 35 期
2+
3+
## 卷首语
4+
5+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/javacsharp.png)
6+
7+
从诞生的第一天起, `C#` 就被认为是 `Java` 的模仿者。从历史来看,我们不能否认这一个观点。现在,每个编程语言都借鉴了其他的编程语言,那么从 `.NET Core` 之后,`C#` 又从 `Java` 中借鉴了什么呢?主要包含三个
8+
9+
1. Record 类型
10+
11+
Record 类型是用来表示纯数据的结构,`C#` 编译器能够将它转换成一个 `class` 类型,并且重写了 `Equals` 方法。
12+
13+
2. 字面字符串
14+
15+
`C#` 中,我们使用双引号 `"` 来表示一个字符串,但是对于一些复杂的字符串,比如换行,特殊字符,我们需要通过转义的方式来表示。这样带来了很多使用的不便。`C#` 引入的字面字符串的方式
16+
17+
```csharp
18+
var text = """
19+
{
20+
"name": "fung kao"
21+
}
22+
""";
23+
```
24+
25+
3. 枚举类型的箭头表达
26+
27+
对于枚举类型,我们一般采用 `swtich` 的方式,比如
28+
29+
```csharp
30+
enum Role
31+
{
32+
User,
33+
Admin
34+
}
35+
36+
var role = Role.User;
37+
38+
switch(role)
39+
{
40+
case Role.User:
41+
Console.WriteLine("User");
42+
break;
43+
case Role.Admin:
44+
Console.WriteLine("Admin");
45+
break;
46+
default:
47+
Console.WriteLine("Unknown");
48+
break;
49+
}
50+
```
51+
52+
这是这个常见的用法,C# 引入了模式匹配的方式,我们可以这样使用
53+
54+
```csharp
55+
var text = role swtich
56+
{
57+
Role.User => "User",
58+
Role.Admin => "Admin"
59+
_ => "unknown"
60+
}
61+
```
62+
63+
## 行业资讯
64+
65+
1、[.NET 虚拟大会](https://devblogs.microsoft.com/dotnet/lets-learn-dotnet-anywhere-in-the-world/)
66+
67+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/virutalevent.png)
68+
69+
通常而言,英语是 `.NET` 社区常用的沟通语言。但是最近 `.NET` 社区举办了全球的虚拟大会,而且在不同的时区和不同语言,值得大家参加。
70+
71+
## 文章推荐
72+
73+
1、[.NETTimer](https://www.meziantou.net/too-many-timers-in-dotnet.htm)
74+
75+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/timer.png)
76+
77+
C# 中包含了很多 `Timer` 类,一般都用来进行一些定时的操作。主要分为两大类:
78+
79+
1. UI 定时类
80+
81+
- `System.Windows.Forms.Timer`
82+
- `System.Windows.Threading.DispatcherTimer`
83+
它们都是 UI 线程执行回调,所以它们能够更新 UI 上的元素,而且每次只执行一次,因此不用担心线程安全的问题
84+
85+
2. 通用定时器
86+
87+
- `System.Threading.Timer`
88+
- `System.Threading.PeriodicTimer`
89+
- `System.Timers.Timer`
90+
91+
其中 `System.Threading.Timer` 是最基础的定时器,它将回调委托给线程池执行。但是如果回调执行的时间超过定时器的间隔,那么会发生同时执行多次的情况。
92+
93+
```csharp
94+
var timer = new System.Threading.Timer(
95+
callback: state => Console.WriteLine("tick"), // callback can be executed in parallel
96+
// if the previous one is not completed
97+
// before the next tick
98+
state: null, // Can be used to pass data to the callback (to avoid using a closure)
99+
dueTime: TimeSpan.Zero, // Start the timer immediately
100+
period: TimeSpan.FromSeconds(1)); // Tick every second
101+
102+
// Pause the timer
103+
timer.Change(dueTime: Timeout.Infinite, period: Timeout.Infinite);
104+
```
105+
106+
`System.Timer.Timer` 是对 `System.Threading.Timer` 的封装,而且暴露了其他几个方法,比如 `AutoReset`, `Enabled`,`SynchronizingObject` 等等,而且它还支持多个回调的调用。
107+
108+
```csharp
109+
var timer = new System.Timers.Timer(TimeSpan.FromSeconds(1));
110+
111+
// Support multiple handlers
112+
timer.Elapsed += (sender, e) => Console.WriteLine("Handler 1");
113+
timer.Elapsed += (sender, e) => Console.WriteLine("Handler 2");
114+
115+
// Support customizing the way the callback is executed (on the ThreadPool if not set)
116+
timerComponent.SynchronizingObject = ...;
117+
118+
// Stop the timer after the first tick
119+
timerComponent.AutoReset = false;
120+
121+
// Start the timer
122+
timer.Start();
123+
```
124+
125+
`System.Threading.PeriodicTimer` 是最近加入的类型,它的主要功能是允许定时器在循环中使用,而且执行异步。
126+
127+
```csharp
128+
using var cts = new CancellationTokenSource();
129+
using var periodicTimer = new PeriodicTimer(TimeSpan.FromSeconds(1));
130+
131+
// Simple usage, no concurrent callbacks, supports async _handlers_
132+
while (await periodicTimer.WaitForNextTickAsync(cts.Token))
133+
{
134+
Console.WriteLine("Tick");
135+
await AsyncOperation();
136+
}
137+
```
138+
139+
通过 `while` 循环判断,避免了回调的并行执行。
140+
141+
2、[.NET Standard 介绍](https://andrewlock.net/understanding-the-dotnet-ecosystem-the-introduction-of-dotnet-standard/)
142+
143+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/netstandard.png)
144+
145+
`.NET Standard` 作为一个短暂的技术名词,在 `.NET` 历史中存在过一段时间。主要目的是解决 `.NET` 各个平台的之间代码的复用性,比如 `.NET Framework`, `Mono` 或者 `.NET Core`。它是一组 `API` 定义的集合,而各个平台包含这些 `API` 的实现。
146+
147+
3、[String 和对象互转换](https://csharp.christiannagel.com/2023/04/14/iparsable/)
148+
149+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/stringobject.png)
150+
151+
将一个对象实例和字符串之间相互转换是很常见的要求,在 `C#` 中定义了接口来进行这些转换。
152+
153+
1. 对象实例转换字符串
154+
155+
- IFormattable
156+
- ISpanFormattable
157+
158+
只要对象实现了其中的接口,那么可以将对象实例按照要求转换成字符串类型
159+
160+
2. 字符串转换成对象
161+
162+
- IParsable
163+
- ISpanParsable
164+
165+
`.NET 7` 为接口类型提供了静态方法,所以在 `.NET 7` 之前,将一个字符串转换成对象的话,通常是这么处理的
166+
167+
```csharp
168+
class Person {
169+
public string FirstName { get; }
170+
public string FullName { get; }
171+
public string Country { get; }
172+
173+
public Person(string firstName, string fullName, string country) {
174+
FirstName = firstName;
175+
FullName = fullName;
176+
Country = country;
177+
}
178+
}
179+
180+
static class ExtensionMethods {
181+
internal static Person Parse(this string s) {
182+
string[] strings = s.Split(new[] { ',', ';' });
183+
if(strings.Length != 3) { throw new OverflowException("Expect: FirstName,LastName,Country"); }
184+
return new Person(strings[0], strings[1], strings[2]);
185+
}
186+
}
187+
```
188+
189+
通常我们需要编写 `string` 类型的扩展方法,那么在 `.NET 7` 中,我们可以通过集成 `IParsable` 接口完成更优雅的实现方式。
190+
191+
```csharp
192+
sealed class Person : IParsable<Person> {
193+
public string FirstName { get; }
194+
public string FullName { get; }
195+
public string Country { get; }
196+
197+
// Private constructor used from the Parse() method below
198+
private Person(string firstName, string fullName, string country) {
199+
FirstName = firstName;
200+
FullName = fullName;
201+
Country = country;
202+
}
203+
204+
// IParsable<Person> implementation
205+
public static Person Parse(string s, IFormatProvider? provider) {
206+
string[] strings = s.Split(new[] { ',', ';' });
207+
if(strings.Length != 3) { throw new OverflowException("Expect: FirstName,LastName,Country"); }
208+
return new Person(strings[0], strings[1], strings[2]);
209+
}
210+
211+
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Person result) {
212+
result = null;
213+
if (s == null) { return false; }
214+
try {
215+
result = Parse(s, provider);
216+
return true;
217+
} catch { return false; }
218+
}
219+
}
220+
221+
Person person = "Bill,Gates,US".Parse<Person>();
222+
```
223+
224+
4、[Azure OpenAI 使用](https://devblogs.microsoft.com/dotnet/getting-started-azure-openai-dotnet/)
225+
226+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/openai.png)
227+
228+
作为一名 `.NET` 开发者,该如何上手 `Azure OpenAI` 呢?这篇官方博客给出了建议。
229+
230+
5ASP.NET Core 中间件处理流程
231+
232+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/aspnetcore.png)
233+
234+
6、[WASM 介绍](https://speakerdeck.com/christianweyer/wasm-wasi-wtf-webassembly-101-for-net-developers)
235+
236+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/wasm.png)
237+
238+
WASM 是新的技术,`.NET` 也不能落后,这个幻灯片介绍了 `WASM` 和 `C#` 入门知识。
239+
240+
7、[Mutation Test](https://blog.jetbrains.com/dotnet/2023/05/05/stefan-polz-how-to-test-csharp-unit-tests-with-mutation-testing-webinar-recording/)
241+
242+
Mutation Test 是用来检测单元测试的质量,这个视频详细介绍这个概念。
243+
244+
## 开源项目
245+
246+
1、[Powershell 中的 chatgpt](https://dfinke.github.io/powershellai,%20powershell,%20chatgpt/2023/04/04/PowerShellAI-ChatGPT-Conversation-Mode.html)
247+
248+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/ai.png)
249+
250+
`ChatGPT` 火了,各种针对 `OpenAI` 的 API 开发的 AI 应用程序也数不胜数。 `PowerShellAI` 是一个开源的 PowerShell 库,使用它我们可以在 `Powershell` 中使用我们的人工智能助手。
251+
252+
2、.NET 知名开源库
253+
254+
![image](https://dotnetweeklyimages.blob.core.windows.net/035/package.png)

docs/images/035/ai.png

12.3 KB
Loading

docs/images/035/aspnetcore.png

152 KB
Loading

docs/images/035/javacsharp.png

41.6 KB
Loading

docs/images/035/netstandard.png

14.6 KB
Loading

docs/images/035/openai.png

1000 KB
Loading

docs/images/035/package.png

541 KB
Loading

docs/images/035/stringobject.png

20.1 KB
Loading

0 commit comments

Comments
 (0)