当我们的 .NET
应用程序从 X
版本升级到 Y
版本,如果发现了在 GC
上表现出现了 Regression
, 事否怀疑 .NET GC
模块导致的呢? Maoni
这篇文章介绍了如何解决这个问题。
只从 .NET Core 2.0
开始,.NET
应用程序可以自行加载其他 GC
实现。所以在遇到 .NET GC
发生 regression 的时候,可以配置 clrgc.dll
开进行替换。
{
"runtimeOptions": {
"configProperties": {
"System.GC.Name": "clrgc.dll"
}
}
}
或者使用环境变量
set DOTNET_GCName=clrgc.dll
如果 GC 仍然出现问题,则需要像 .NET
团队提出 issue,否则通过常规的 GC 问题分析方法来分析应用程序。
Visual Studio
更新的了 Add New File
功能,不再弹出一个包含全部模板的对话框,而是直接一个简单的对话框,只要输入文件名即可创建,它包含了这些特色
- 无需浏览模板
- 支持嵌套文件夹
- 支持任何文件拓展名
- 支持多个文件创建
Markdown
是广泛使用的格式,在过去很长一段时间,Visual Studio
不支持这种格式。最新版的 Visual Studio
将会改变这个现状。
call
和 callvirt
是 IL 代码中常见的两个调用方法,那么这两者的区别在哪呢?这篇给文章带你分析其中的奥秘。
Required
修饰符是 C# 11
引入的,它的主要目的是为了让某些字段或者属性在构造的时候,必须要进行初始化,否则编译器会报错,这篇文章详细介绍这个新的功能。
Stopwatch
是 C# 编程中广泛使用的类,它用来记录操作的耗时,比如
var stopwatch = Stopwatch.StartNew();
//.....
stopwatch.Stop();
Timespan ts = stopwatch.Elapsed;
对于简单的应用程序,这样没有任何问题。但是 Stopwatch
是一个 Class
类型,也就是说每次操作都会在堆上分配一个空间。对于 hot path
路径中的代码,对内存压力还是比较大。
Stopwatch
类中有一些静态方法,它可以避免内存的分配
var start = Stopwatch.GetTimestamp();
///
var elapse = Stopwatch.GetElapsedTime(start);
如果更近一步,将它们封装一个 ValueStopwatch
结构
public struct ValueStopwatch
{
private static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;
private long _startTimestamp;
public bool IsActive => _startTimestamp != 0;
private ValueStopwatch(long startTimestamp)
{
_startTimestamp = startTimestamp;
}
public static ValueStopwatch StartNew() => new ValueStopwatch(Stopwatch.GetTimestamp());
public TimeSpan GetElapsedTime()
{
if (!IsActive)
{
throw new InvalidOperationException("An uninitialized, or 'default', ValueStopwatch cannot be used to get elapsed time.");
}
long end = Stopwatch.GetTimestamp();
long timestampDelta = end - _startTimestamp;
long ticks = (long)(TimestampToTicks * timestampDelta);
return new TimeSpan(ticks);
}
}
dotnet sln
命令可以将动态将工程文件 (csproj
) 文件添加到解决方案中,但是如果工程文件特别多,那么怎么使用 dotnet
命令添加到解决方案中呢?
答案是可以通过这个命令
dotnet new sln -n Everything
dotnet sln ./Everything.sln add (ls -r **/*.csproj)
Minimal API
是 .NET 6
推出的新功能,通过 IEndpointRouteBuilder
接口的拓展方法可以代替 Controller
类。但是这样带来一个问题,如果 API
特别多,那么单个文件中代码会非常多。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/products", async (AppDbContext dbContext) =>
{
return Results.Ok(await dbContext.Products.ToListAsync());
});
app.MapPost("/products", async (Product product, AppDbContext dbContext) =>
{
dbContext.Products.Add(product);
await dbContext.SaveChangesAsync();
return Results.Ok(product);
});
app.Run();
一种解决方案是通过拓展方法,将一组 API
封装成拓展方法
public static class ProductsModule
{
public static void RegisterProductsEndpoints(this IEndpointRouteBuilder endpoints)
{
endpoints.MapGet("/products", async (AppDbContext dbContext) =>
{
return Results.Ok(await dbContext.Products.ToListAsync());
});
endpoints.MapPost("/products", async (Product product, AppDbContext dbContext) =>
{
dbContext.Products.Add(product);
await dbContext.SaveChangesAsync();
return Results.Ok(product);
});
}
}
另外一种方法是通过 Carter 库
public class ProductsModule : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapGet("/products", async (AppDbContext dbContext) =>
{
return Results.Ok(await dbContext.Products.ToListAsync());
});
app.MapPost("/products", async (Product product, AppDbContext dbContext) =>
{
dbContext.Products.Add(product);
await dbContext.SaveChangesAsync();
return Results.Ok(product);
});
}
}
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCarter();
var app = builder.Build();
app.MapCarter();
app.Run();
在应用程序开发过程中,有时候我们需要将 JSON
表示为 C# 的应用程序中的类。Visual Studio
可以自动将拷贝的 JSON
字符串转换成一个类。
1、函数式编程
Erik Meijer 博士介绍的函数式编程课程。
Quartz.NET
是 .NET
社区的开源任务调度库。