TypeScript 3.4 rc получил опцию компилятора --incremental
( сообщение в блоге ).
Когда он включен, TypeScript сгенерирует файл .tsbuildinfo
, если его еще нет (поэтому вы все равно играете штраф 10 с + один раз). Но если он существует, холодный tsc --watch
пробег будет очень быстрым (больше не задержка 10 с).
Либо с флагом командной строки --incremental
, либо в вашем tsconfig.json
:
{
"compilerOptions": {
"incremental": true
}
}
Как уже отмечалось, 32-битное целое число может существовать в двух вариантах. Четыре байта в любом месте памяти или регистра ЦП (не только в стеке), быстрая версия. И его можно встроить в System.Object, коробочную версию. Объявление System.Int32 совместимо с последним. В упаковке он имеет типичный заголовок объекта, за которым следуют 4 байта, в которых хранится значение. И эти 4 байта точно соответствуют члену m_value. Возможно, вы понимаете, почему здесь нет конфликта: m_value всегда быстрая версия без упаковки. Потому что не существует такой вещи, как целое число в штучной упаковке.
Как компилятор языка, так и JIT-компилятор хорошо осведомлены о свойствах Int32.Компилятор отвечает за решение, когда целое число нужно упаковать и распаковать, для этого он генерирует соответствующие инструкции IL. И он знает, какие доступны инструкции IL, которые позволяют работать с целым числом, не упаковывая его предварительно. Как легко понять из методов, реализованных System.Int32, например, он не имеет переопределения для operator == (). Это делается с помощью кода операции CEQ. Но у него есть переопределение для Equals (), необходимое для переопределения метода Object.Equals (), когда целое число помещено в рамку. Ваш компилятор должен иметь такую же осведомленность.
Другие ответы являются неосведомленными и/или вводящими в заблуждение.
Это может помочь понять это под первым чтением мой ответ на [1 144], Как ValueTypes происходят из Объекта (ReferenceType) и все еще ValueTypes?
System.Int32
структура, которая содержит 32-разрядное целое число со знаком. Это делает не , содержат себя. Для ссылки на тип значения в IL синтаксис valuetype [assembly]Namespace.TypeName
.
Встроенные типы II.7.2 CLI встроенным типам определили соответствующие типы значения в Библиотеке базовых классов. На них нужно сослаться в подписях только с помощью их специальной кодировки (т.е. не используя синтаксис valuetype TypeReference общего назначения). Раздел I указывает встроенные типы.
Это означает, что, если у Вас есть метод, который берет 32-разрядное целое число, Вы не должны использовать стандартное valuetype [mscorlib]System.Int32
синтаксис, но специальное кодирование для 32-разрядного встроенного целого числа со знаком int32
.
В C#, это означает, это, будет ли Вы тип System.Int32
или int
, любой скомпилирован в [1 112], не valuetype [mscorlib]System.Int32
.
Вы, возможно, услышали, что int
псевдоним для [1 115] в C#, но в действительности, оба псевдонимы встроенного типа int32
.
значения CLS Поэтому, в то время как структура как [1 162]
public struct MyStruct
{
internal MyStruct m_value;
}
Действительно скомпилировала бы в (и таким образом была бы недопустима):
.class public sequential ansi sealed beforefieldinit MyStruct extends [mscorlib]System.ValueType
{
.field assembly valuetype MyStruct m_value;
}
namespace System
{
public struct Int32
{
internal int m_value;
}
}
Вместо этого компиляции к (игнорирующие интерфейсы):
.class public sequential ansi sealed beforefieldinit System.Int32 extends [mscorlib]System.ValueType
{
.field assembly int32 m_value;
}
компилятор C# делает не , нуждаются в особом случае для компиляции System.Int32
, потому что спецификация CLI предусматривает, что все ссылки на [1 118] заменяются специальным кодированием для встроенного типа int32
.Следовательно. System.Int32
значения CLS, структура, которая не содержит другой System.Int32
, но int32
. В IL у Вас может быть 2 перегрузки метода, одно взятие System.Int32
и другое взятие int32
и сделать, чтобы они сосуществовали:
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89)
.ver 2:0:0:0
}
.assembly test {}
.module test.dll
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003
.corflags 0x00000001
.class MyNamespace.Program
{
.method static void Main() cil managed
{
.entrypoint
ldc.i4.5
call int32 MyNamespace.Program::Lol(valuetype [mscorlib]System.Int32) // Call the one taking the System.Int32 type.
call int32 MyNamespace.Program::Lol(int32) // Call the overload taking the built in int32 type.
call void [mscorlib]System.Console::Write(int32)
call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
pop
ret
}
.method static int32 Lol(valuetype [mscorlib]System.Int32 x) cil managed
{
ldarg.0
ldc.i4.1
add
ret
}
.method static int32 Lol(int32 x) cil managed
{
ldarg.0
ldc.i4.1
add
ret
}
}
Декомпиляторы как ILSpy, dnSpy, Отражатель.NET, и т.д. могут вводить в заблуждение. Они (во время записи) будут декомпилироваться и int32
и System.Int32
или как ключевое слово int
C# или как тип System.Int32
, потому что это - то, как мы определяем целые числа в C#.
, Но int32
встроенный тип значения для 32-разрядных целых чисел со знаком (т.е. VES имеет прямую поддержку этих типов, с инструкциями как [1 130], sub
, ldc.i4.x
, и т.д.); System.Int32
соответствующий тип значения, определенный в библиотеке классов. Соответствие System.Int32
тип используется для упаковки, и для методов как [1 135], CompareTo()
, и т.д.
, Если Вы пишете программу в чистом IL, можно абсолютно заставить собственное значение ввести, который содержит int32
точно таким же образом, где Вы все еще используете int32
, но методы вызова на пользовательском "соответствующем" типе значения.
.class MyNamespace.Program
{
.method hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
ldc.i4.0
call void MyNamespace.Program::PrintWhetherGreaterThanZero(int32)
ldc.i4.m1 // -1
call void MyNamespace.Program::PrintWhetherGreaterThanZero(int32)
ldc.i4.3
call void MyNamespace.Program::PrintWhetherGreaterThanZero(int32)
ret
}
.method private hidebysig static void PrintWhetherGreaterThanZero(int32 'value') cil managed noinlining
{
.maxstack 8
ldarga 0
call instance bool MyCoolInt32::IsGreaterThanZero()
brfalse.s printOtherMessage
ldstr "Value is greater than zero"
call void [mscorlib]System.Console::WriteLine(string)
ret
printOtherMessage:
ldstr "Value is not greater than zero"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
}
.class public MyCoolInt32 extends [mscorlib]System.ValueType
{
.field assembly int32 myCoolIntsValue;
.method public hidebysig bool IsGreaterThanZero()
{
.maxstack 8
ldarg.0
ldind.i4
ldc.i4.0
bgt.s isNonZero
ldc.i4.0
ret
isNonZero:
ldc.i4.1
ret
}
}
Это не отличается от эти System.Int32
тип, за исключением того, что компилятор C# не рассматривает MyCoolInt32
соответствие int32
тип, но к CLR, это не имеет значения. Это приведет к сбою PEVerify.exe, однако, но это будет работать очень хорошо. Декомпиляторы покажут броски, и очевидный указатель разыменовывает при декомпиляции вышеупомянутого, потому что они не рассматривают MyCoolInt32
и int32
связанный также.
, Но функционально, нет никакого различия, и нет никакого волшебства, продолжающегося негласно в CLR.
Зайдите в эту ветку для кропотливого обсуждения этой тайны.
Магия на самом деле в боксировании/небоксировании.
System.Int32
(и его псевдоним int
) - это тип значения, что означает, что он обычно выделяется в стеке. CLR берет ваше объявление System.Int32
и просто превращает его в 32 бита стека.
Однако, когда вы пишете object testInt = 4;
, компилятор автоматически превращает ваше значение 4
в ссылку, поскольку object
является ссылочным типом. Что у вас есть, так это ссылка, указывающая на System.Int32
, которая теперь занимает 32 бита места где-то на куче. Но автобоксированная ссылка на System.Int32
называется (...подождите...) System.Int32
.
Что делает ваш пример кода, так это создает ссылку System.Int32
и изменяет значение System.Int32
, на которое оно указывает. Это объясняет странное поведение.