Skip to content

Commit ac7472d

Browse files
committed
publish episode 39
1 parent 80cc437 commit ac7472d

File tree

2 files changed

+333
-1
lines changed

2 files changed

+333
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
### 2023
1818

19-
**七月份**[第 038 期](docs/episode-038.md) :high_brightness:
19+
**七月份**[039 期](docs/episode-039.md) | [038 期](docs/episode-038.md) :high_brightness:
2020

2121
**六月份**[第 037 期](docs/episode-037.md)
2222

docs/episode-039.md

+332
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
# .NET 每周分享第 39 期
2+
3+
## 卷首语
4+
5+
`C#` 12 的新功能预览
6+
7+
1. `nameof` 可以访问成员变量,包括初始化,静态变量和注解
8+
2. 内联数组: 可以标记 `[System.Runtime.CompilerServices.InlineArray(10)]` 方式在内存中创建 10 个元素
9+
3. `Interceptors`: 这是一项实验功能,可以让特定的方法调用路由到不同的代码。
10+
11+
## 行业资讯
12+
13+
1、[Azure AD 改名 Microsoft Entra](https://devblogs.microsoft.com/dotnet/azure-ad-microsoft-entra/)
14+
15+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/100f7b9f-7874-4892-91ad-772f2b6781af)
16+
17+
微软改名部继续工作,将 `Azure AD` 改名为 `Microsoft Entra`。这个改名对于 `.NET` 开发者而言,没有任何影响。
18+
19+
## 文章推荐
20+
21+
1、[最小的 Hello world 程序](https://blog.washi.dev/posts/tinysharp/)
22+
23+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/107f17ea-0b91-4dae-b388-38d3bcaf94f7)
24+
25+
`Hello World` 是每个编程语言的第一个 demo, 那么对于 `C#` 而言,一个简单的 `Hello world` 应用程序会暂用多大的磁盘空间呢?
26+
27+
```csharp
28+
using System;
29+
namespace ConsoleApp1;
30+
internal static class Program
31+
{
32+
public static void Main(string[] args)
33+
{
34+
Console.WriteLine("Hello, World!");
35+
}
36+
}
37+
```
38+
39+
这段代码在 `.NET Framework 4.7.2` 版本下, 生成可执行文件的大小为 `5kb`,那么作者是如何一步步将它减少体积的呢?
40+
41+
- 移除 `Nullable` 属性
42+
- 手动创建 `.NET Module`
43+
- 移除引入和基础重定位
44+
- 删除名称 metadata
45+
- 删除更多的 metadata
46+
- 不适用 `System.Console.WriteLine`
47+
48+
最终的 `Hello World` 文件大小定格在 476 字节。
49+
50+
51+
2、[分析器认为有错误写法](https://www.youtube.com/watch?v=v7GAQfWnco0&ab_channel=NickChapsas)
52+
53+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/c5560288-8190-4a04-a7e0-22649fe1736d)
54+
55+
`.NET 8` 中, `Code Analysis` 为 C# 代码更多的检查,比如下面 6 种例子
56+
57+
1. ConstantExpected
58+
59+
```csharp
60+
public static void ProcessValue([ConstantExpected (Min = 20)]int value)
61+
{
62+
}
63+
```
64+
如果方法的参数增加了 `ConstantExpected` 的注解,那么要求方法的调用必须传入常量
65+
66+
2. Linq 中的 Any
67+
68+
```csharp
69+
public static bool HasElement(string[] strings)
70+
{
71+
return strings.Any();
72+
}
73+
```
74+
75+
通常 `Linq` 中的 `Any()` 方法可以判断是否存在元素,但是如果是具体的类型,比如 `Array`, `List` 等,则分析器提示使用 `strings.Length !=0` 的方式。
76+
77+
3. Split
78+
79+
```csharp
80+
public static string[] SplitText(string text)
81+
{
82+
return text.Split(new char[] { ' ', ',' });
83+
}
84+
```
85+
86+
在这个方法中,每次调用 `SplitText` 方法,都会创建一个 `char[]` 对象,这样增加了内存压力,所以分析器建议将 array 对象设置为一个只读对象,并且只初始化一次。
87+
88+
89+
4. Cast
90+
91+
```csharp
92+
var test = new int[] { 1 }.Cast<string>();
93+
```
94+
95+
这个代码在运行的时候会抛出 `InvalidCastExpection` ,现在分析器会检测到这个错误并且在编译的时候给出这样提示。
96+
97+
98+
在 Runtime repo 中的 [issue](https://github.com/dotnet/runtime/issues/78442),它列出可以增加的分析功能。
99+
100+
3、[你应该学习 Blazor 吗?](https://www.youtube.com/watch?v=OUUlO8fQOfE&ab_channel=IAmTimCorey)
101+
102+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/aecb0b83-4296-4481-a80a-845839f7396f)
103+
104+
`Blazor` 的未来是怎样的?我们需要学习吗?这个视频给了一些介绍。
105+
106+
4、[高效连接字符串和字符](https://www.meziantou.net/micro-optimization-concatenating-a-string-with-a-char-using-string-concat.htm)
107+
108+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6b28e5f0-a7dd-4d6f-8048-79277efaee20)
109+
110+
C# 中字符串的 `+` 操作符是转换为 `string.Concat` 方法调用。如果是一个字符串连接一个字符呢?有没有什么其他方法,并且能够使用更高的性能呢?
111+
`string.Concat` 有另一个方法签名,接受的参数类型是 `ReadOnlySpan<Char>`, 所以只需要将 `char` 类型转化为 `ReadOnlySpan<char>` 即可
112+
113+
```csharp
114+
[MemoryDiagnoser]
115+
public class StringConcatBenchmark
116+
{
117+
private string Part1 = "abc";
118+
private char Part2_Char = 'd';
119+
private string Part2_String = "d";
120+
private string Part3 = "efg";
121+
122+
[Benchmark(Baseline = true)]
123+
public string Operator_String_Char_String() => Part1 + Part2_Char + Part3;
124+
125+
[Benchmark]
126+
public string Operator_String_String_String() => Part1 + Part2_String + Part3;
127+
128+
[Benchmark]
129+
public string String_Concat() => string.Concat(Part1, new ReadOnlySpan<char>(in Part2_Char), Part3);
130+
}
131+
```
132+
133+
benchmark 结果如下
134+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/f4bbaf0a-8b0a-4bd4-b1b9-d247cb0afedd)
135+
136+
5、[Powershell 定制自动任务](https://www.techtarget.com/searchwindowsserver/tutorial/Learn-how-to-create-a-scheduled-task-with-PowerShell)
137+
138+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/efd264f9-4d63-4e2e-af3e-86d8a13eec3e)
139+
140+
如果我们想要在 Widnows 中注册一个定时任务,使用 PowerShell 那么该怎么做呢?
141+
142+
1. 注册一个Action
143+
```powershell
144+
$Action = New-ScheduledTaskAction -Execute 'pwsh.exe' -Argument '-NonInteractive -NoLogo -NoProfile -File "C:\MyScript.ps1"'
145+
```
146+
首先通过 `New-ScheduledTaskAction` 注册一个 Action,它知名了执行的命令和相关的参数
147+
148+
2. 定制一个 Trigger
149+
150+
```powershell
151+
$Trigger = New-ScheduledTaskTrigger -Once -At 3am
152+
```
153+
154+
定义一个 `Trigger` 用来什么时候启动这个任务,比如每次早上 3 点运行
155+
156+
3. 配置
157+
158+
```csharp
159+
$Settings = New-ScheduledTaskSettingsSet
160+
```
161+
通过从 `Setting` 配置任务的额外信息,比如执行超时,是否 retry 等等。
162+
163+
4. 创建 Task
164+
165+
```csharp
166+
$Task = New-ScheduledTask -Action $Action -Trigger $Trigger -Settings $Settings
167+
```
168+
根据 `Action`, `Trigger` 和 `Setting` 创建要给 Task
169+
170+
5. 注册任务
171+
172+
```csharp
173+
Register-ScheduledTask -TaskName 'My PowerShell Script' -InputObject $Task
174+
```
175+
目前任务是保存在内存中,通过 `Register-ScheduleTask` 将这个对象注册到操作系统中。
176+
177+
6、[写出 Clean Code 的 8 个技巧](https://www.milanjovanovic.tech/blog/8-tips-to-write-clean-code)
178+
179+
如果有这样一段 C# 代码,该如何优化呢?
180+
181+
```csharp
182+
public void Process(Order? order)
183+
{
184+
if (order != null)
185+
{
186+
if (order.IsVerified)
187+
{
188+
if (order.Items.Count > 0)
189+
{
190+
if (order.Items.Count > 15)
191+
{
192+
throw new Exception(
193+
"The order " + order.Id + " has too many items");
194+
}
195+
196+
if (order.Status != "ReadyToProcess")
197+
{
198+
throw new Exception(
199+
"The order " + order.Id + " isn't ready to process");
200+
}
201+
202+
order.IsProcessed = true;
203+
}
204+
}
205+
}
206+
}
207+
```
208+
209+
那么 8 个建议重构更好的代码
210+
- 尽早返回
211+
- 合并更多的 If 判断条件
212+
- 使用 `Linq` 让代码更加简洁
213+
- 使用特定的方法来重构 If 判断条件
214+
- 抛出自定义异常
215+
- 将魔数转换为常量
216+
- 将字符串转化为枚举类型
217+
- 使用返回结果类型,而不是直接修改输入
218+
219+
7、[如何正确的使用 HttpClient 类](https://www.milanjovanovic.tech/blog/the-right-way-to-use-httpclient-in-dotnet)
220+
221+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/6c6497f7-7f93-4c6b-8a7e-e1c191cd793d)
222+
223+
`HttpClient` 类是 `C#` 代码中广泛使用的类型,那么该怎么最好的使用这个类型呢?
224+
225+
1. 普通方式
226+
227+
```csharp
228+
var client = new HttpClient();
229+
//...
230+
```
231+
232+
2. 使用 `IHttpClientFactory`
233+
234+
```csharp
235+
var client = _factory.CreateClient();
236+
//....
237+
```
238+
239+
`Microsoft.Extensions.Http` 推荐的使用方式
240+
241+
242+
3. Name Client
243+
244+
```csharpservices.AddHttpClient("github", (serviceProvider, client) =>
245+
{
246+
var settings = serviceProvider
247+
.GetRequiredService<IOptions<GitHubSettings>>().Value;
248+
client.BaseAddress = new Uri("https://api.github.com");
249+
});
250+
251+
var client = _factory.CreateClient("github");
252+
```
253+
254+
3. Type client
255+
256+
```csharp
257+
services.AddHttpClient<GitHubService>((serviceProvider, client) =>
258+
{
259+
var settings = serviceProvider
260+
.GetRequiredService<IOptions<GitHubSettings>>().Value;
261+
client.BaseAddress = new Uri("https://api.github.com");
262+
});
263+
264+
public class GitHubService
265+
{
266+
private readonly HttpClient client;
267+
268+
public GitHubService(HttpClient client)
269+
{
270+
_client = client;
271+
}
272+
273+
public async Task<GitHubUser?> GetUserAsync(string username)
274+
{
275+
GitHubUser? user = await client
276+
.GetFromJsonAsync<GitHubUser>($"users/{username}");
277+
278+
return user;
279+
}
280+
}
281+
```
282+
这样在应用程序中,只需要在依赖注入框架中获取 `GithubSerivce` 对象即可,注意这是一个 `transient` 注入方式。
283+
284+
## 开源项目
285+
286+
1、[MSBuilder 编辑器](https://marketplace.visualstudio.com/items?itemName=mhutch.MSBuildEditor)
287+
288+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/43e574ec-2a6a-4b8e-aef2-3f6b69956eef)
289+
290+
`MSBuild Editor` 插件是用来管理 C# 的 MSBuild 文件,主要有下面几个功能
291+
292+
- 智能提示
293+
- 导航
294+
- 快速查询
295+
- 验证和分析
296+
- 重构和代码修复
297+
- schemas 修改
298+
- 导入
299+
300+
2、[TextUtility](https://github.com/PowerShell/TextUtility)
301+
302+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/2824c29a-5bbe-45a8-a8c0-793a711901eb)
303+
304+
`Microsoft.Powershell.TextUtility``Powershell` 中的文本处理库,只要包含一下三个函数
305+
306+
1. Compare-Text
307+
308+
它实现了 [diff-match-path](https://github.com/google/diff-match-patch)
309+
310+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/36386ad2-3f90-485c-9c31-8f5e5974fc87)
311+
312+
2. ConvertFrom-Base64/ConvertTo-Base64
313+
314+
它主要是将字符串转换成 Base64 或者将 Base64 转成成字符串。
315+
316+
```powershell
317+
> ConvertTo-Base64 "dotnetweekly"
318+
# ZG90bmV0d2Vla2x5
319+
> ConvertFrom-Base64 "ZG90bmV0d2Vla2x5"
320+
# dotnetweekly
321+
```
322+
323+
3. ConvertFrom-TextTable
324+
325+
这个主要是将文本的表格转换成一个实体对象
326+
327+
```csharp
328+
> $string = $("a".."z";"A".."Z";0..9) -join ""
329+
> 1..10 | %{$string}|convertfrom-texttable -noheader -columnoffset 0,15,23,40,55 | ft
330+
```
331+
![image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/1827e126-e582-40a5-9570-ba7e92bb6102)
332+

0 commit comments

Comments
 (0)