C# 未调用静态构造函数
我正在尝试使用AutoMapper进行模型viewmodel映射,并希望在该类型的静态构造函数中执行一次映射配置。当使用该类型调用Mapper.Map(AutoMapper)时,不会调用该类型的静态构造函数 我的理解是Mapper.Map将尝试通过反射访问类型及其成员,并且在第一次尝试使用时将调用静态构造函数。这是一个基本的问题,但对我的理解提出了挑战。提供了代码片段C# 未调用静态构造函数,c#,.net,automapper,C#,.net,Automapper,我正在尝试使用AutoMapper进行模型viewmodel映射,并希望在该类型的静态构造函数中执行一次映射配置。当使用该类型调用Mapper.Map(AutoMapper)时,不会调用该类型的静态构造函数 我的理解是Mapper.Map将尝试通过反射访问类型及其成员,并且在第一次尝试使用时将调用静态构造函数。这是一个基本的问题,但对我的理解提出了挑战。提供了代码片段 class SampleViewModel { static SampleViewModel() {
class SampleViewModel
{
static SampleViewModel()
{
Mapper.Initialize(cfg => cfg.CreateMap<Sample, SampleViewModel>().ReverseMap());
}
public SampleViewModel()
{
}
public int PropertyA { get; set; }
public int PropertyB { get; set; }
}
Sample s = new Sample { PropertyA = 10, PropertyB = 20 };
var obj = Mapper.Map<SampleViewModel>(s); // fails
class SampleViewModel
{
静态SampleViewModel()
{
初始化(cfg=>cfg.CreateMap().ReverseMap());
}
公共SampleViewModel()
{
}
公共int属性{get;set;}
公共int属性b{get;set;}
}
样本s=新样本{PropertyA=10,PropertyB=20};
var obj=Mapper.Map;//失败
当第一次通过反射访问类型和成员时,静态构造函数是否被调用(如果提供)?您没有访问
SampleViewModel
的任何成员-仅引用类型本身是不够的
Mapper.Map
只访问自己内部的映射“字典”——在处理SampleViewModel
之前,它失败了。静态构造函数从不运行,因此无法将“自身”添加到映射器中
现在,如果这不涉及反射,那么调用静态构造函数是正确的,因为它会在编译包含访问的方法时发生,例如:
var obj = Mapper.Map<SampleViewModel>(s);
Console.WriteLine(obj.SomeField);
var obj=Mapper.Map;
控制台写入线(对象SomeField);
在这种情况下,由于该方法引用的是SampleViewModel
上的一个字段,因此在JIT编译包含该方法的过程中将调用SampleViewModel
的静态构造函数,因此,Mapper.Map
行将正确执行,因为现在存在映射。不用说,这不是解决你问题的正确方法。这只会让代码变得非常糟糕,无法维护:)
免责声明:尽管这可能会立即解决问题,但这取决于当前在Windows上实现MS.NET时的非合同行为。合同规定在对类型成员进行任何访问之前调用类型初始值设定项,但这仍然意味着CIL的有效实现只能在Mapper.Map
之后调用类型初始值设定项,只要它发生在obj.SomeField
之前,如果编译器能够确保这样做是安全的,那么obj.SomeField
可能会得到优化。强制调用类型初始值设定项的唯一真正方法是调用RuntimeHelpers.RunClassConstructor
,但此时,您还可以添加一个静态Init
方法或其他方法
真正的问题是,首先不应该在静态构造函数中初始化这样的东西。映射应该在某种确定性初始化过程中设置,比如显式调用的InitMappings
方法。否则,您将面临大量的Heisenbug,更不用说CLR中的细微变化会毫无理由地破坏整个应用程序
静态构造函数不是用来“注册”的,只是初始化类型本身——其他任何东西都是滥用,会给您(或.NET兼容性团队)带来麻烦。静态构造函数在创建该类的第一个实例之前,在实现定义的时间运行,或者在访问该类型的任何静态成员之前。看 映射程序试图在实例化要映射到的类之前找到映射,因此无法找到映射,因为在此之前从未实例化过该类
只需将映射初始化代码移动到
AutoMapperBootstrap.cs
文件或其他文件中,并在应用程序初始化中调用它。您确定要编辑吗?为什么静态类型初始值设定项在JIT访问实例成员的方法时运行?类型初始值设定项不是在实现定义的时间运行的,所以它可能(计划)在Map()
和WriteLine()之间运行。。这就解释了。映射程序在处理类型之前会检查内部映射。@CodeMaster当前的MS.NET实现就是这样的,但您是对的,我需要添加一个免责声明-这不是契约行为,只是“意外”。根据约定,只需要在访问成员之前调用类型初始值设定项,因此CIL实现只在obj.SomeField
发生之前调用它是完全有效的。这就是我所说的“对CLR的细微更改破坏了整个应用程序”的一个例子:D