December 10th, 2009

glider

Кошмар продолжается

Не успел я поборот баг, описанный в соседнем посте, как наткнулся на связанный. Как было описано в том посте, проблема в том, что рефлекшн-эмит записывает сигнатуры, в которых участвуют многомерные массивы вот так (иллюстрация для двумерных массивов): T[..., ...], что отличается от того как это делает csc - T[0...,0...]. Оказывается, для рантайма эта небольшая разница оказывается очень значительной.

Конкретно моя проблема заключалась в том, что некорректно генерился MethodRef, и поэтому из рефлекшн-эмита я не мог вызвать методы, имеющие в своей сигнатуре параметр/ретурн многомерного типа. Задавив трабл воркараундом, я, к сожалению, не додумался до того, что этот воркараунд не имеет смысла, ибо есть еще куча непокрытых важных для меня случаев, где этот баг проявится. Например, в попытке перекрыть метод, у которого есть сигнатура с многомерным массивом. Фак. Пора пускать в ход тяжелую артиллерию...

P.S. Год назад этот баг уже засабмиттили в Майкрософт: http://support.microsoft.com/kb/960240. Вот что пишут по этому поводу из Редмонда: "Microsoft has recognized this problem, and it is currently planned that a future release of the .NET Framework will include a System.Reflection.Emit namespace that will have corrected this. Avoid using multidimensional arrays in classes where this anomaly might be a problem for you."
glider

Резолюшен

После некоторого обдумывания того, что делать с багом, описанным в предыдущем посте, решил вот что. На пока единственный практичный вариант - подсунуть тайп-билдеру пачку прокси вместо набора его метод-билдеров.

Проблема кроется в методе класса SignatureHelper, но все энтри поинты к нему идут через статические методы, т.е. тут никак не подкопаться. А видели бы вы сколько использований у этого SignatureHelper... К сожалению, из этого следует, что если похожий баг возникнет в другом месте - с филдами, пропертями или еще хз где, то придется делать новые фиксы.

Было бы очень круто, если бы можно было в рантайме создать клон рефлекшн-эмита и подменить бажный кусок кода на правильный, после чего дальше юзать пофикшенный клон. Я вижу здесь две потенциальные проблемы: 1) видимость внутренних методов, 2) методы, объявленные как [MethodImpl(MethodImplOptions.InternalCall)], но обе из них разрешимы. Для доступа к непубличным мемберам можно юзать LCG, который при наличии фулл-траста может скипать проверки видимости, а вместо клонирования интернальных методов можно сгенерить их обертки.