Необычные операторы С# в декомпилированном источнике...?
Я только что декомпилировал какой-то сторонний источник для отладки проблемы, используя DotPeek. Код вывода содержит некоторые необычные операторы, которые AFAIK недействительны С#, поэтому мне интересно, что они означают...
Экстракт выглядит (с комментариями Dotpeek, поскольку они, вероятно, актуальны);
protected internal void DoReceive(ref byte[] Buffer, int MaxSize, out int Written)
{
Written = 0;
.
.
.
// ISSUE: explicit reference operation
// ISSUE: variable of a reference type
int& local = @Written;
int num = SomeMethod();
.
.
.
// ISSUE: explicit reference operation
^local = num;
}
Итак, 3 необычных оператора там... int& = @Written
Кажется, присваивается указатель на переменную, которая называется бессмысленно с символом @?
Но что такое ^local = num;
???
ОК, вот эквивалентный фрагмент от ILSpy, который имеет больше смысла, я думаю, что декомпиляция с С# не привела к действительному эквиваленту?
'С#'
int& local = @Written;
byte[] numArray2 = this.FInSpool;
int num = (int) __Global.Min(numArray2 == null ? 0L : (long) numArray2.Length, (long) MaxSize);
^local = num;
IL
byte[] expr_22 = this.FInSpool;
Written = (int)__Global.Min((long)((expr_22 == null) ? 0 : expr_22.Length), (long)MaxSize);
Итак, я думаю, что "С#" не совсем допустимо? Этот IL был бы действительным С#, не зная, почему DotPeek произвел результат, который он сделал. Возможно, я буду придерживаться ILSpy для этого...?
Ответы
Ответ 1
Если вы посмотрите на raw IL (от ildasm, а не эквивалент С# через IL Spy), это может помочь вам понять, что пытается сказать декомпилятор. Параметры "Out" представлены с использованием (управляемой) типизированной ссылки, которая явно не отображается как тип в С#. "Экземпляры" этого типа обычно могут передаваться только как параметры методам, принимающим типизированные ссылки (параметры "ref" или "out" ). См. OpCodes.Mkrefany для получения дополнительной информации.
То, что dotPeek жалуется, заключается в том, что эта "введенная" ссылка была сохранена из аргумента в локальный слот переменной, а затем записывается позже через локальный слот. "@" И "^" - это заполнители, используемые для указания этого неожиданного поведения, обнаруженного декомпилятором (тот, который описываются комментариями ВОПРОСА.)
Возможно, код был скомпилирован из С++/CLI, и, следовательно, IL выглядит отличным от типичного вывода компилятора С#. Возможно, это и есть некоторый уровень незначительной запутывания, чтобы запутать декомпиляторы (хотя я так не думаю). Я не думаю, что это функционально не отличается от загрузки ссылки из ее аргумента в стек операций непосредственно (избегая использования локальный слот переменной), но я мог ошибаться.
Ответ 2
Помещая @
перед именем, вы можете использовать зарезервированное имя для переменной. Например, если бы я хотел иметь переменную с именем return
, мне нужно было бы это сделать.
public int Weird()
{
int @return = 0;
return @return;
}
Подробнее см. этот вопрос.
Поместите ^
перед именем... umm, нет подсказки. (будет обновляться по мере того, как я исследую). Я мог бы найти любую информацию о том, что означает ^
, когда он не используется как XOR)
Ответ 3
Это явно проблема декомпиляции. Из-за широкого набора поддерживаемых языков декомпилятор на какой-либо конкретный язык может не всегда находить точное совпадение, но все же пытается произвести некоторый вывод. Декомпилятор МОЖЕТ попробовать произвести несколько эквивалентный вывод, как в этом случае может быть:
protected internal void DoReceive(ref byte[] Buffer, int MaxSize, out int Written)
{
Written = 0;
.
int num = SomeMethod();
.
Written = num;
}
но СЛЕДУЕТ это действительно сделать? в этом случае декомпилятор действительно предоставил вам подсказку, чтобы вы могли решить, важно ли это для вашего конкретного случая, так как МОЖЕТ быть некоторыми побочными эффектами.