Вы не обращаетесь к любым членам SampleViewModel
- этого недостаточно, чтобы просто ссылаться на сам тип.
Mapper.Map
имеет доступ только к собственному внутреннему «словарю» сопоставлений - прежде чем он сможет добраться до точки, где он имеет дело с SampleViewModel
, он терпит неудачу. Статический конструктор никогда не запускается, поэтому он не может добавить «сам» в Mapper
.
Теперь, если это не связано с отражением, вы были бы правы, что статический конструктор будет называться - просто потому, что это произошло бы во время компиляции метода, содержащего доступ, например:
var obj = Mapper.Map<SampleViewModel>(s);
Console.WriteLine(obj.SomeField);
В этом случае, поскольку метод ссылается на поле на SampleViewModel
, статический конструктор для SampleViewModel
будет вызываться во время компиляции JIT содержащего метода, и как таковая строка Mapper.Map<SampleViewModel>(s)
будет выполняться правильно, так как отображение теперь присутствует. Излишне говорить это неправильное решение вашей проблемы. Было бы просто сделать код абсолютно ужасен поддерживать :)
ОТКАЗ: Несмотря на то, что это может решить эту проблему прямо сейчас, это зависит от внедоговорного поведения в текущей реализации MS.NET на Windows. Контракт указывает, что инициализатор типа вызывается перед любым доступом к члену типа, но это все равно означает, что действительная реализация CIL может вызывать только инициализатор типа послеMapper.Map
, если это происходит до obj.SomeField
- и даже то может быть, что obj.SomeField
оптимизируется, если компилятор может гарантировать, что это безопасно. Единственный реальный способ: привести в исполнение вызов инициализатора типа должен вызвать RuntimeHelpers.RunClassConstructor
, но к этому моменту вы могли бы также добавить статический метод Init
или что-то в этом роде.
Настоящая проблема заключается в том, что вы не должны инициализировать такие вещи, как это, в статическом конструкторе в первую очередь. Сопоставления должны быть заданы в каком-то детерминистском процессе инициализации, например, явно вызванном методе InitMappings
. В противном случае вы открываете себе огромную банку из Heisenbugs, не говоря уже о тонких изменениях в CLR, разрушающих все ваше приложение без видимых причин.
Статические конструкторы просто не предназначены для «регистрации», а просто инициализации самого типа - что-то еще является злоупотреблением и вызовет проблемы (или команды совместимости .NET).
Вы уверены, что редактируете? Почему инициализатор статического типа запускается во время JIT-метода, когда к нему обращается элемент _instance_? Разве инициализатор типа не запускается в определенное время реализации, поэтому он может (планироваться) работать между «Map()» и «WriteLine()»? – CodeCaster
ах .. это объясняет. Картер проверяет внутреннее сопоставление, прежде чем он будет иметь дело с типом. –
@CodeCaster Вот что происходит в текущих реализациях MS.NET, но вы правы, что мне нужно добавить отказ от ответственности - это не контрактное поведение, просто «случайное». По контракту инициализатор типа требуется только для вызова до доступа к члену, поэтому для реализации CIL вполне справедливо вызывать его только до того, как произойдет «obj.SomeField». Это пример того, что я имел в виду под «тонкими изменениями в CLR, разбивающими все ваше приложение»: D – Luaan