|
| 1 | +# .NET 每周分享第 41 期 |
| 2 | + |
| 3 | +## 卷首语 |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +最近 `.NET` 社区的大新闻是微软将在明年退役 `Visual Studio for Mac` 这个产品,该消息在社区的引发了巨大的讨论。 |
| 8 | + |
| 9 | +## 行业资讯 |
| 10 | + |
| 11 | +1、[Rider 65% 折扣](https://blog.jetbrains.com/dotnet/2023/09/01/65-off-rider/) |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +当微软宣布不再支持 `Visual Studio for Mac` 之后,`JetBrains` 就立马宣布旗下 `Rider` IDE 进行 65% 的折扣销售,可谓是**杀人诛心**。 |
| 16 | + |
| 17 | + |
| 18 | +## 文章推荐 |
| 19 | + |
| 20 | +1、[Rust 代码运行在 .NET CLR 中](https://fractalfir.github.io/generated_html/rustc_codegen_clr_v0_0_1.html) |
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | +这是一篇非常有意思的博客,作者尝试了将 Rust 代码生成的结果运行在 .NET CLR 上 |
| 25 | + |
| 26 | +2、[使用 String.Globalization.StringInfo 计算 Unicode 字符的长度](https://khalidabuhakmeh.com/measuring-unicode-string-lengths-with-csharp) |
| 27 | + |
| 28 | +[image](https://github.com/DotNETWeekly-io/DotNetWeekly/assets/11272110/49c5fc63-029b-4a18-836e-5a67fddb21b2) |
| 29 | + |
| 30 | +在处理 `Unicode` 字符串的时候,我们需要知道字符串所占用的字节长度。尤其是涉及到 Emoji 时候,它有时候是多个 Unicode 字符串拼接而成,所以在 C# 中我们可以通过 `String.Globalization.StringInfo.GetNextTextElementLength` 方法来获得字符所占用的字节数量。 |
| 31 | + |
| 32 | +```csharp |
| 33 | +using System.Globalization; |
| 34 | + |
| 35 | +var characters = new[] { "a", "1", "👩🚀", "あ", "👨👩👧👦", "✨" }; |
| 36 | + |
| 37 | +var lengths = characters.Select(c => (value: c, length: StringInfo.GetNextTextElementLength(c))); |
| 38 | + |
| 39 | +foreach(var (val, length) in lengths) |
| 40 | +{ |
| 41 | + Console.WriteLine($"{val} (length: {length}"); |
| 42 | +} |
| 43 | +``` |
| 44 | + |
| 45 | + |
| 46 | +3、[Visual Studio 9 个隐藏功能](https://blog.elmah.io/9-hidden-features-in-visual-studio-that-you-may-not-know/) |
| 47 | + |
| 48 | + |
| 49 | + |
| 50 | +`Visual Studio` 是一款广泛使用的 IDE,那么对于 Visual Studio 还有一些隐藏的功能。 |
| 51 | + |
| 52 | +1. Drag & Drop 添加工程应用 |
| 53 | +2. GitHub Action 在 Visual Studio 解决方案视图 |
| 54 | +3. CPU/Memory Profiler: 通过在不同断点之间开启 CPU profile |
| 55 | +4. 拷贝带缩进 |
| 56 | +5. Visual Studio 通常会保存上次的 profile,但是 Visual Studio 支持在启动的时候配置不同的 profile. |
| 57 | +6. 清理不同的 Azure Functional 工具 |
| 58 | +7. 内嵌展示诊断信息 |
| 59 | +8. 智能 JSON 校验 |
| 60 | +9. 不同事件播放不同声音 |
| 61 | + |
| 62 | + |
| 63 | +4、[HttpClient DelegatingHandler](https://www.youtube.com/watch?v=goxI3rOMnmY&ab_channel=NickChapsas) |
| 64 | + |
| 65 | + |
| 66 | + |
| 67 | + 我们都知道 `ASP.NET Core` 通过中间件的方式,处理一个个请求,对于定制化的业务逻辑,我们可以编写自己的中间件。同样的在 `HttpClient` 类中,我们 `DelegateHandler` 也可以当作中间件,可以对client 发出的请求进行定制化处理,比如缓存请求。 |
| 68 | + |
| 69 | +```csharp |
| 70 | +internal class CacheHttpMessageHandler : DelegatingHandler |
| 71 | +{ |
| 72 | + private readonly IMemoryCache _cache; |
| 73 | + public CacheHttpMessageHandler(IMemoryCache cache) |
| 74 | + { |
| 75 | + _cache = cache; |
| 76 | + } |
| 77 | + |
| 78 | + protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) |
| 79 | + { |
| 80 | + var queryString = HttpUtility.ParseQueryString(request.RequestUri.Query); |
| 81 | + var key = queryString["city"]; |
| 82 | + if (_cache.TryGetValue<string>(key, out var content)) |
| 83 | + { |
| 84 | + return new HttpResponseMessage(System.Net.HttpStatusCode.NotModified) |
| 85 | + { |
| 86 | + Content = new StringContent(content) |
| 87 | + }; |
| 88 | + } |
| 89 | + |
| 90 | + var response = await base.SendAsync(request, cancellationToken); |
| 91 | + content = await response.Content.ReadAsStringAsync(); |
| 92 | + _cache.Set<string>(key, content, TimeSpan.FromSeconds(10)); |
| 93 | + return response; |
| 94 | + } |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +那么可以将它注册到容器中 |
| 99 | +```csharp |
| 100 | +IServiceCollection service = new ServiceCollection(); |
| 101 | + |
| 102 | +service.AddMemoryCache(); |
| 103 | +service.AddTransient<CacheHttpMessageHandler>(); |
| 104 | +service.AddHttpClient("httpbin") |
| 105 | + .AddHttpMessageHandler<CacheHttpMessageHandler>(); |
| 106 | + |
| 107 | +IServiceProvider provider = service.BuildServiceProvider(); |
| 108 | + |
| 109 | +var httpClientFactory = provider.GetService<IHttpClientFactory>(); |
| 110 | + |
| 111 | +HttpClient httpClient = httpClientFactory.CreateClient("httpbin"); |
| 112 | + |
| 113 | +for (int i = 0; i < 20; i++) |
| 114 | +{ |
| 115 | + using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://httpbin.org/get?city=beijing"); |
| 116 | + using var response = await httpClient.SendAsync(httpRequestMessage); |
| 117 | + Console.WriteLine(response.StatusCode); |
| 118 | + await Task.Delay(TimeSpan.FromSeconds(1)); |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | +5、[.NET 生成时 AI ](https://devblogs.microsoft.com/dotnet/demystifying-retrieval-augmented-generation-with-dotnet/) |
| 123 | + |
| 124 | + |
| 125 | + |
| 126 | +这是一份来自 `Stephen Toub` 的文章,介绍了如何使用 `Semantic Kernal` 和 `Azuer OpenAI` 来一步步创建一个 `.NET` 的对话应用程序。 |
| 127 | + |
| 128 | +6、[.NET Runtime Bug](https://www.youtube.com/watch?v=1oR7L6kHnCI&ab_channel=NickChapsas) |
| 129 | + |
| 130 | + |
| 131 | +```csharp |
| 132 | +using System.Collections; |
| 133 | + |
| 134 | +IStructuralEquatable one = new ValueTuple<int, int, int, int, int>(1, 2, 3, 4, 5); |
| 135 | +IStructuralEquatable two = new ValueTuple<int, int, int, int, int>(1, 2, 3, 5, 5); |
| 136 | + |
| 137 | +Console.WriteLine(one.Equals(two, EqualityComparer<int>.Default)); |
| 138 | +``` |
| 139 | + |
| 140 | +上面这段代码的返回输出是什么?应该是 `false`,因为第四个元素的值不一样,但是在目前的 `.NET` SDK 中,编译出来的结果是 `true`。这是 `.NET` BCL 的 bug,因为 `Tuple` 类型的 `Equal` 方法跳过了第四个元素。 |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | +目前 `Fix` PR 已经合并。 |
| 145 | + |
| 146 | + |
| 147 | +## 开源项目 |
| 148 | + |
| 149 | +1、[ConsoleTables](https://github.com/khalidabuhakmeh/ConsoleTables) |
| 150 | + |
| 151 | + |
| 152 | + |
| 153 | +在 `C#` 的控制台应用程序中,我们有时候需要输出一些表格的内容来更加直观的展示内容。`ConsoleTables` 这个开源库可以帮助我们很方便的输出。使用方法也是非常简单 |
| 154 | + |
| 155 | +```csharp |
| 156 | +var table = new ConsoleTable("one", "two", "three"); |
| 157 | +table.AddRow(1, 2, 3) |
| 158 | + .AddRow("this line should be longer", "yes it is", "oh"); |
| 159 | +table.Write(); |
| 160 | +``` |
| 161 | + |
| 162 | + |
| 163 | + |
| 164 | +淡然可以控制输出表格的样式 |
| 165 | + |
| 166 | +```csharp |
| 167 | +var rows = Enumerable.Repeat(new Something(), 10); |
| 168 | +ConsoleTable |
| 169 | + .From<Something>(rows) |
| 170 | + .Configure(o => o.NumberAlignment = Alignment.Right) |
| 171 | + .Write(Format.Alternative); |
| 172 | + |
| 173 | +``` |
| 174 | + |
| 175 | +2、[Visual Studio 中预览图片](https://github.com/MadsKristensen/ImagePreview) |
| 176 | + |
| 177 | + |
| 178 | + |
| 179 | +这是 Visual Studio 的可以插件,当你把鼠标放在上面的时候,它会根据图片的地址获取,然后以缩略图的方式展示出来。支持下面的图片路径格式 |
| 180 | + |
| 181 | +- 绝对 URI 地址 |
| 182 | +- 相对 URI 地址 |
| 183 | +- 文件路径 |
| 184 | +- 数据 URI |
| 185 | +- 包 URI |
| 186 | + |
| 187 | +3、[CSharpier](https://github.com/belav/csharpier) |
| 188 | + |
| 189 | + |
| 190 | +`CSharpier` 是一个 `.NET` 的代码格式化工具。首先安装工具 |
| 191 | + |
| 192 | +``` |
| 193 | +dotnet tool install csharpier -g |
| 194 | +``` |
| 195 | + |
| 196 | +然后使用 `dotnet charpier .` 命令可以格式化相应的 `.NET` 项目。 |
0 commit comments