Pull to refresh

Comments 12

Ещё можно вполне документированно прогнать вызов через Remoting, начала получив через прокси экземпляр IMethodCallMessage, а затем в соседнем потоке отдав его на откуп RemotingServices.
Ну и unsafe-код с получением pinned-указателя и дальнейшей работой с T* тоже вполне документирован, да. Причём этот вариант более безопасен чем магия выше. А ещё лучше не колдовать вообще и сделать нормально, но это выходит за рамки темы вашей статьи, как я понимаю.
>>А ещё лучше не колдовать вообще и сделать нормально
Такой способ выходит за рамки тематики одного из указанных хабов. И одной из целей было обойтись без unsafe.
UFO just landed and posted this here
Изначальной целью был некий IDisposable, который бы сначала менял значение поля на какое-то временное, а на Dispose возвращал бы старое значение взад. Т.е. нужно в любом случае передавать ссылку на поле в другую область видимости. Если просто оставить преобразованный RuntimeArgumentHandle в статическом поле и преобразовать его обратно уже в другой области видимости (при том, что фрейм стека, в котором он был создан, уже «умер») то ArgIterator ничего не сможет вытащить — аргументов уже 0 (а при попытке получения количества оставшихся аргументов или при получении одного из аргументов можно уронить clr). С TypedReference при этом нечто похожее, и тоже можно уронить clr (правда, указатель, что является единственным полем, остаётся неравным нулю).

p.s. всё это катит только в дотнете, в Mono свои заморочки и такого фокуса я там пока не провернул.
В моно вообще весёлые вещи есть. Например, когда я писал кодогенерацию для одной штуки, то обнаружил, что .NET игнорирует разницу между ldfld и ldsfld, извлекая нужную информацию из FieldInfo, а вот Mono — нет. При этом ошибок никаких он не выдаст, а вместо статического поля загрузит нестатическое с тем же индексом. А пост-эффекты были просто замечательные, например, у меня в переменной типа List<int> лежал объект типа Action, что видно было лишь в отладчике, программа же валилась с SIGSEGV.
Количество таких историй может исчисляться тысячами. Например, используя в моно класс из другой сборки (собранной студийным компилятором), метод которой что возвращает T*, то Console.WriteLine (SomeMethod()) может отобразить… ничего. У меня такое было — такое чувство что вызов каким-то образом отменялся. Зато если преобразовывать указатель в строку и выбрасывать его как new Exception(someTakenString) то можно было этот указатель получить. Что интересно, можно такой фокус использовать без /unsafe в опциях компилятора, но использовать этот фокус с политикой, что требует security transparent код и никакой другой, то можно получить исключение, которое свидетельствует о том, что clr НЕ В СОСТОЯНИИ определить, является ли такой код типобезопасным. (Речь идёт о Unity3D, второй случай (с политиками безопасности) является случаем билда в веб-плеер).
Кстати, объявить vararg-делегат спокойно можно на уровне IL. Ограничение на __arglist там — исключительно недоделка компилятора.
Что мешает передавать
Func<T> GetValue, Action<T> SetValue
вместо магии?
Понял свою ошибку. Нельзя создать лямбду.

Однако это есть правильно, потому что другой поток не может быть уверен, что он пишет по адресу который еще не очищен из-за выхода за предел видимости в родительском потоке. Очевидное решение — не хранить данные в value type классах/полях если хочется многопоточность.

По поводу же вашей изначальной цели: «некий IDisposable, который бы сначала менял значение поля на какое-то временное»
Можно просто хранить в IDisposable ваш класс и функтор, который изменяет поле. Класс, конечно, не должен быть структурой.
Sign up to leave a comment.

Articles