C# 未调用静态构造函数

C# 未调用静态构造函数,c#,.net,automapper,C#,.net,Automapper,我正在尝试使用AutoMapper进行模型viewmodel映射,并希望在该类型的静态构造函数中执行一次映射配置。当使用该类型调用Mapper.Map(AutoMapper)时,不会调用该类型的静态构造函数 我的理解是Mapper.Map将尝试通过反射访问类型及其成员,并且在第一次尝试使用时将调用静态构造函数。这是一个基本的问题,但对我的理解提出了挑战。提供了代码片段 class SampleViewModel { static SampleViewModel() {

我正在尝试使用AutoMapper进行模型viewmodel映射,并希望在该类型的静态构造函数中执行一次映射配置。当使用该类型调用Mapper.Map(AutoMapper)时,不会调用该类型的静态构造函数

我的理解是Mapper.Map将尝试通过反射访问类型及其成员,并且在第一次尝试使用时将调用静态构造函数。这是一个基本的问题,但对我的理解提出了挑战。提供了代码片段

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