Весь код, написанный на языках .NET, компилируется в MSIL, но есть ли конкретные задачи / операции, которые вы можете выполнять только с использованием MSIL напрямую?
Позвольте нам также сделать вещи проще в MSIL, чем C #, VB.NET, F #, j # или любой другой язык .NET.
Пока у нас есть это:
- Хвостовая рекурсия
- Общий Co / Contravariance
- Перегрузки, которые отличаются только типами возврата
- Переопределить модификаторы доступа
- Есть класс, который не может наследоваться от System.Object
- Отфильтрованные исключения (может быть сделано в vb.net)
- Вызов виртуального метода текущего типа статического класса.
- Получить дескриптор в штучной упаковке версии типа значения.
- Сделайте попытку / ошибку.
- Использование запрещенных имен.
- Определите свои собственные конструкторы без параметров для типов значений .
- Определите события с
raise
элементом. - Некоторые преобразования разрешены CLR, но не C #.
- Сделайте не
main()
метод как.entrypoint
. - работать с нативным
int
и нативнымunsigned int
типами напрямую. - Играть с переходными указателями
- директива emitbyte в MethodBodyItem
- Бросать и ловить не System.Exception типы
- Inherit Enums (не проверено)
- Вы можете рассматривать массив байтов как (в 4 раза меньший) массив целых.
- У вас может быть поле / метод / свойство / событие, все они имеют одно и то же имя (не проверено).
- Вы можете перейти обратно в блок try из своего собственного блока catch.
- У вас есть доступ к спецификатору доступа famandassem (
protected internal
является fam или сборкой) - Прямой доступ к
<Module>
классу для определения глобальных функций или инициализатора модуля.
Ответы:
MSIL допускает перегрузки, которые отличаются только типами возврата из-за
или
источник
Большинство языков .Net, включая C # и VB, не используют функцию хвостовой рекурсии кода MSIL.
Хвостовая рекурсия - это оптимизация, распространенная в функциональных языках. Это происходит, когда метод A завершается возвратом значения метода B, так что стек метода A может быть освобожден после выполнения вызова метода B.
Код MSIL явно поддерживает хвостовую рекурсию, и для некоторых алгоритмов это может быть важной оптимизацией. Но так как C # и VB не генерируют инструкции, чтобы сделать это, это должно быть сделано вручную (или с использованием F # или другого языка).
Вот пример того, как хвостовая рекурсия может быть реализована вручную в C #:
Обычной практикой является удаление рекурсии путем перемещения локальных данных из аппаратного стека в структуру данных стека, выделенного для кучи. При устранении рекурсии хвостового вызова, как показано выше, стек исключается полностью, что является довольно хорошей оптимизацией. Кроме того, возвращаемое значение не должно проходить по длинной цепочке вызовов, но оно возвращается напрямую.
Но, в любом случае, CIL предоставляет эту функцию как часть языка, но в C # или VB она должна быть реализована вручную. (Джиттер также может выполнять эту оптимизацию самостоятельно, но это совсем другая проблема.)
источник
В MSIL у вас может быть класс, который не может наследоваться от System.Object.
Пример кода: скомпилируйте его с помощью ilasm.exe. ОБНОВЛЕНИЕ: Вы должны использовать "/ NOAUTOINHERIT", чтобы запретить ассемблеру автоматически наследовать.
источник
TypeLoadException
). PEVerify возвращает: [MD]: Ошибка: TypeDef, который не является интерфейсом и не классом объекта, расширяет маркер Nil.Возможно объединить
protected
иinternal
получить доступ к модификаторам. В C #, если вы пишете,protected internal
член доступен из сборки и из производных классов. Via MSIL вы можете получить элемент , который доступен из производных классов в сборке только . (Я думаю, что это может быть очень полезно!)источник
private protected
Ох, я не заметил этого в то время. (Если вы добавите тег jon-skeet, это более вероятно, но я проверяю его не так часто.)
Похоже, у вас уже есть довольно хорошие ответы. К тому же:
object
C #, это иногда будет работать. Смотрите uint [] / int [] ТАК вопрос для примера.Я добавлю к этому, если я думаю о чем-нибудь еще ...
источник
<>a
имя в C # ...CLR уже поддерживает стандартную co / contravariance, но C # не получает эту функцию до 4.0
источник
В IL вы можете бросать и ловить любой тип, а не только типы, полученные из
System.Exception
.источник
try
/catch
без круглых скобок в операторе catch вы также поймаете исключения, не похожие на исключения. Бросать, однако, действительно возможно только тогда, когда вы наследуете отException
.IL имеет различие между
call
иcallvirt
для вызовов виртуальных методов. Используя первый, вы можете вызвать виртуальный метод текущего типа статического класса. вместо виртуальной функции в типе динамического класса.C # не имеет возможности сделать это:
VB, как и IL, может выполнять невиртуальные вызовы с использованием
MyClass.Method()
синтаксиса. В приведенном выше, это было быMyClass.ToString()
.источник
В try / catch вы можете повторно войти в блок try из его собственного блока catch. Итак, вы можете сделать это:
AFAIK, вы не можете сделать это в C # или VB
источник
GOTO
Catch
егоTry
. Запустите тестовый код онлайн здесь .С IL и VB.NET вы можете добавлять фильтры при перехвате исключений, но C # v3 не поддерживает эту функцию.
Этот пример VB.NET взят из http://blogs.msdn.com/clrteam/archive/2009/02/05/catch-rethrow-and-filters-why-you-should-care.aspx (обратите внимание
When ShouldCatch(ex) = True
на Поймать оговорку):источник
= True
, это заставляет мои глаза кровоточить!Насколько я знаю, нет способа сделать инициализаторы модуля (статические конструкторы для всего модуля) непосредственно в C #:
http://blogs.msdn.com/junfeng/archive/2005/11/19/494914.aspx
источник
Native types
Вы можете работать с собственными типами int и native unsigned int напрямую (в c # вы можете работать только с IntPtr, который не совпадает).
Transient Pointers
Вы можете играть с временными указателями, которые являются указателями на управляемые типы, но гарантированно не перемещаются в памяти, поскольку они не находятся в управляемой куче. Не совсем уверен, как вы могли бы с пользой использовать это, не связываясь с неуправляемым кодом, но он не доступен другим языкам напрямую только через такие вещи, как stackalloc.
<Module>
вы можете возиться с классом, если пожелаете (вы можете сделать это с помощью рефлексии, не нуждаясь в IL)
.emitbyte
.entrypoint
У вас есть немного больше гибкости, вы можете применить его к методам, например, не вызванным Main.
прочитайте спецификацию, я уверен, вы найдете еще несколько.
источник
<Module>
это подразумевается как специальный класс для языков, которые принимают глобальные методы (как VB), но на самом деле C # не может получить к нему прямой доступ.Вы можете взломать метод override co / contra-variance, который C # не позволяет (это НЕ то же самое, что универсальная дисперсия!). У меня есть больше информации о реализации этого здесь , а также части 1 и 2
источник
Я думаю, что единственным, кого я продолжал желать (по совершенно неправильным причинам), было наследование в Enums. Это не кажется трудным делом в SMIL (так как Enums - просто классы), но это не то, чего хочет от вас синтаксис C #.
источник
Вот еще немного:
источник
20) Вы можете рассматривать массив байтов как (в 4 раза меньший) массив целых.
Я использовал это недавно для быстрой реализации XOR, так как функция CLR xor работает с целыми числами, и мне нужно было выполнить XOR в байтовом потоке.
Полученный код измеряется примерно в 10 раз быстрее, чем эквивалентный код C # (выполняется XOR для каждого байта).
===
У меня нет достаточно стека и потока stackoverflow, чтобы отредактировать вопрос и добавить его в список под номером # 20, если бы кто-то еще мог, это было бы здорово ;-)
источник
Что-то, что использует обфускатор - у вас может быть поле / метод / свойство / событие с одинаковым именем.
источник
Enum наследование не возможно:
Вы можете наследовать от класса Enum. Но результат не ведет себя как Enum в частности. Он ведет себя даже не как тип значения, а как обычный класс. Странная вещь: IsEnum: True, IsValueType: True, IsClass: False
Но это не особенно полезно (если вы не хотите запутать человека или саму среду выполнения).
источник
Вы также можете получить класс из делегата System.Multicast в IL, но вы не можете сделать это в C #:
источник
Вы также можете определять методы уровня модуля (или глобальные) в IL, а C #, напротив, позволяет определять методы только при условии, что они связаны хотя бы с одним типом.
источник