Товарищи, возникли некоторые вопросы по поводу runtime
, связанные с именами переменных
и проверкой их типов
, однако для лучшего понимания распишу всю ситуацию.
В одном из моих вопросов я приводил пример подмены методов во время runtime
. Чуть "поигравшись" с этим, я обнаружил, что ключевое слово this
в рамках инъецированного метода ссылается именно на тот объект, в класс которого он и был инъецирован. Я решил проверить, будет ли это работать и с переменными
Так что я создал тестовый класс
:
public class TestClass
{
public int Value { get; set; }
}
И класс для подмены
:
public class InjectorClass
{
public int Value { get; set; }
public void SetterInjecter(int Data)
{
Value = ~Data;
Console.WriteLine("Hello from injected setter!");
}
}
Далее я произвел замену:
Type testType = typeof(TestClass);
Type injectType = typeof(InjectorClass);
Injector.Inject(testType.GetMethod("set_Value"), injectType.GetMethod("SetterInjecter"));
TestClass test = new TestClass();
test.Value = int.MinValue;
Console.WriteLine("test.Value == {0}", test.Value);
И все это действительно сработало, ибо я получил следующий вывод:
Hello from injected setter!
test.Value == 2147483647
(~a = -a - 1
=> ~int.MinValue = int.MaxValue = 2147483647
)
Тем самым мы убедились, что можем получить доступ к переменной из инъецированного метода по имени
После этого я пошел дальше и решил изменить тип переменной Value
в классе InjectorClass
, тем самым посмотрев, что получится при присвоении переменной типа int
значения совершенного иного типа. Для этого я создал такую структуру:
[StructLayout(LayoutKind.Explicit, Size = 4)]
public struct IntByte
{
[FieldOffset(0), MarshalAs(UnmanagedType.I1)]
public byte _0;
[FieldOffset(1), MarshalAs(UnmanagedType.I1)]
public byte _1;
[FieldOffset(2), MarshalAs(UnmanagedType.I1)]
public byte _2;
[FieldOffset(3), MarshalAs(UnmanagedType.I1)]
public byte _3;
public IntByte(int From)
{
string bits = Convert.ToString(From, 2).PadLeft(32, '0');
_3 = Convert.ToByte(bits.Substring(0, 8), 2);
_2 = Convert.ToByte(bits.Substring(8, 8), 2);
_1 = Convert.ToByte(bits.Substring(16, 8), 2);
_0 = Convert.ToByte(bits.Substring(24, 8), 2);
}
}
Ее суть в том, что в памяти она выглядит ровно как заданный в инициализаторе int From
.
Также я чуть изменил InjectorClass
:
public class InjectorClass
{
public IntByte Value { get; set; }
public void SetterInjecter(int Data)
{
Value = new IntByte(~Data);
Console.WriteLine("Hello from injected setter!\n\nbyte 0: {0};\nbyte 1: {1};\nbyte 2: {2};\nbyte 3: {3};\n\n", Value._0, Value._1, Value._2, Value._3);
}
}
Тем самым получается, что в runtime
после подмены мы присваиваем переменной типа int
значение переменной типа IntByte
. Запустив код вновь (код подмены не менялся с прошлого пункта), я ожидал увидеть крах приложения, сообщение об ошибке или хоть какой сигнализатор того, что я совершаю что-то неправомерное. Однако в консоли я вновь видел вполне себе веселый и бодрый вывод:
Hello from injected setter!
byte 0: 255;
byte 1: 255;
byte 2: 255;
byte 3: 127;
test.Value == 2147483647
Такое поведение мне показалось малость странным, ибо я всегда считал, что проверка типов ведется даже в runtime
, т.к., скажем, такой код:
dynamic a = new IntByte(1);
int b = a;
Пусть он и скомпилируется, однако все же выбросит ошибку во время выполнения...
Едем дальше. Хорошо. Пускай типы уже не проверяются, но если мы, скажем, сошлемся на переменную, которой не существует в текущем экземпляре, ошибка ведь вылетит, правда? Нет. Как ни странно, поменяв InjectorClass
на это:
public class InjectorClass
{
public IntByte X { get; set; }
public void SetterInjecter(int Data)
{
X = new IntByte(~Data);
Console.WriteLine("Hello from injected setter!\n\nbyte 0: {0};\nbyte 1: {1};\nbyte 2: {2};\nbyte 3: {3};\n\n", X._0, X._1, X._2, X._3);
}
}
Я все равно получил тот же самый вывод:
Hello from injected setter!
byte 0: 255;
byte 1: 255;
byte 2: 255;
byte 3: 127;
test.Value == 2147483647
Вот тут я уже впал в окончательную задумчивость, что же там в runtime
творится.
К слову, если добавить в InjectorClass
переменную с названием Value
или типом int
, то изменение X
в инъецированном методе перестает влиять на test.Value
, так что какая-то логика там точно присутствует
Собственно, пора бы и резюмировать возникшие у меня вопросы по данному поводу:
runtime
, если аналогичный по своей сути код с использованием dynamic
все же падает во время исполнения?IntByte
, вы заметите, что присвоение байтов идет с конца. С последнего к нулевому. То есть последовательность байтов для int.MaxValue
выглядит как 255 -> 255 -> 255 -> 127
, хотя по логике все должно быть наоборот. С чем связан такой обратный порядок значащих байтов? Сталкивался с этим, когда в памяти обрабатывал изображения в виде массива байтов, однако просто принимал как должное)
Буду очень благодарен за разъяснение этих интересных моментов)
Виртуальный выделенный сервер (VDS) становится отличным выбором
Добрый день у меня есть контекст Library, таблица BooksС помощью метода Load() я загружаю в Local данные и потом local привязываю к datagrid
Как в XAML прописать путь к картинке через EnvironmentCurrentDirectory
У меня есть небольшая проблема с Walker Class'ом в wordpressМой walker: