问题描述
如果我将这些属性应用于某些服务,然后将其注入到 DI 中,我正在尝试确定将使用哪个 CallerMemberName
或 CallerFilePath
值。例如:
public class MyService: IMyService
{
public MyService([CallerMemberName] string name = null)
{
var name = name; // name is always null here
}
}
...
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyService,MyService>();
}
}
那么,我猜是 name
变量的预期值还是我做错了什么?在这种情况下,我如何使用 CallerMemberName
?有可能吗?
解决方法
如果我将这些属性应用于某些服务,然后将其注入到 DI 中,我正在尝试确定将使用哪个 CallerMemberName
或 CallerFilePath
值。
你不能。您的方法不起作用,因为 ASP.NET Core (Microsoft.Extensions.DependencyInjection
) 使用的默认 DI 系统使用动态注册,这意味着 AOT(C#-to-IL)和 JIT(IL -to-x64) 编译器对 DI 服务的使用者一无所知(请注意,尽管注册在概念上是静态,并且只能在启动时执行 - 这只是一种错觉:您可以轻松破解运行时的默认 DI 容器)。
作为侧边栏:唯一你的方法可行的时间是如果你有某种代码生成系统在构建时创建你的对象工厂和服务工厂不使用任何运行时反射或 IL 生成。在实践中,您看到该方法在单元测试代码中使用的唯一地方,其中测试需要严格控制每个依赖项 - 但它们通常是手工编写的,而且非常乏味和脆弱。通过 Roslyn 代码生成,我希望看到 静态 服务工厂开始被更多地使用,因为它为您提供编译时保证每个依赖项都可用 - 这样您在运行时就不会遇到任何令人讨厌的意外缺少依赖项。
[CallerMemberName]
和 [CallerFilePath]
属性由 AOT 编译器填充,而不是由 JIT 编译器填充,即使是由 JIT 编译器填充也无济于事,因为 DI 服务的使用者不是服务构造函数的调用者。
我做错了吗?
你是。出于我上面描述的原因。
在这种情况下我如何使用 CallerMemberName
?
你不能。 CallerMemberNameAttribute
并非用于此目的。它旨在快速轻松地进行日志记录、分析和跟踪。
有可能吗?
是 - 通过正确扩展 Microsoft.Extensions.DependencyInjection
。请阅读 MEDI 文档了解更多详情。