主题: csharp
-
.NET 依赖注入惯例:生命周期、作用域与“被困依赖”陷阱
Microsoft.Extensions.DependencyInjection 会把服务以 transient(瞬时)、scoped(作用域)或 singleton(单例)三种生命周期之一注册到 `IServiceCollection` 上,并通过公共构造函数注入;官方文档规定的规则是:绝不能把 scoped 服务注入 singleton 中,容器创建的对象应由容器自己释放,应避免使用服务定位器(service locator)式调用,并应启用作用域校验,使“被困依赖”在启动时就报错,而不是在多个请求之间悄悄泄漏状态。
-
使用 JUnit 5 和 xUnit.net 编写单元测试:并列比较注解、生命周期和参数化用例
JUnit Jupiter 用 @Test 标记测试,默认在每个新实例上的测试前后运行 @BeforeEach 和 @AfterEach,并用 @ParameterizedTest 加数据源注解驱动数据用例;xUnit.net 用 [Fact]、构造函数和 IDisposable 在新实例上完成每个测试的准备与清理,用 [Theory] 和 [InlineData] 表达用例,用 fixture 共享昂贵的上下文。在两者中采用相同的测试结构,有助于多语言团队统一约定。
-
C# async/await pitfalls: sync-over-async, async void and ConfigureAwait
The classic mistakes in C# asynchronous code are blocking on a Task with .Result, .Wait() or GetAwaiter().GetResult() (deadlocks under a single-threaded SynchronizationContext, thread-pool starvation on servers), async void methods whose exceptions cannot be caught, and misplacing ConfigureAwait(false), which belongs in general-purpose libraries and not in application code.
-
Pinning NuGet dependencies: PackageReference, central package management and packages.lock.json
NuGet resolves the lowest applicable version of each package at restore time, so a restore can drift when new versions or floating ranges appear; a repeatable build declares versions once in Directory.Packages.props, enables RestorePackagesWithLockFile so packages.lock.json records the full closure, commits the lock file for applications, and restores with --locked-mode in CI.
-
C# 可空引用类型:编译期契约,而非运行时检查
启用 <Nullable>enable</Nullable> 后,C# 编译器将 string 视为不可为 null,将 string? 视为可为 null,跟踪每个表达式的 null 状态,并在不匹配时发出警告。运行时没有变化,string 与 string? 是同一种类型;null 包容运算符 ! 和可空性分析特性([NotNullWhen]、[MemberNotNull])用于告诉编译器它无法自行推断的事实。
机器可读: JSON