Tout le code écrit dans les langages .NET compile vers MSIL, mais y a-t-il des tâches / opérations spécifiques que vous ne pouvez effectuer qu'en utilisant directement MSIL?
Laissez-nous aussi faire les choses plus facilement dans MSIL que C #, VB.NET, F #, j # ou tout autre langage .NET.
Jusqu'à présent, nous avons ceci:
- Récursivité de la queue
- Co / Contravariance générique
- Surcharges qui ne diffèrent que par les types de retour
- Remplacer les modificateurs d'accès
- Avoir une classe qui ne peut pas hériter de System.Object
- Exceptions filtrées (peut être fait dans vb.net)
- Appel d'une méthode virtuelle du type de classe statique actuel.
- Obtenez une poignée sur la version encadrée d'un type valeur.
- Faites un essai / erreur.
- Utilisation de noms interdits.
- Définissez vos propres constructeurs sans paramètre pour les types valeur .
- Définissez des événements avec un
raise
élément. - Certaines conversions sont autorisées par le CLR mais pas par C #.
- Créez une
main()
méthode non comme.entrypoint
. - travailler directement avec les types natifs
int
et natifsunsigned int
. - Jouez avec des pointeurs transitoires
- emitbyte directive dans MethodBodyItem
- Lancer et intercepter les types non System.Exception
- Hériter des énumérations (non vérifiées)
- Vous pouvez traiter un tableau d'octets comme un tableau (4x plus petit) d'entiers.
- Vous pouvez avoir un champ / méthode / propriété / événement tous avoir le même nom (non vérifié).
- Vous pouvez revenir à un bloc try à partir de son propre bloc catch.
- Vous avez accès au spécificateur d'accès famandassem (
protected internal
est fam ou assem) - Accès direct à la
<Module>
classe pour définir des fonctions globales, ou un initialiseur de module.
Réponses:
MSIL autorise les surcharges qui ne diffèrent que par les types de retour en raison de
ou
la source
La plupart des langages .Net, y compris C # et VB, n'utilisent pas la fonctionnalité de récursivité de queue du code MSIL.
La récursivité de la queue est une optimisation courante dans les langages fonctionnels. Cela se produit lorsqu'une méthode A se termine par renvoyer la valeur de la méthode B de sorte que la pile de la méthode A puisse être désallouée une fois l'appel à la méthode B effectué.
Le code MSIL prend en charge explicitement la récursivité de queue, et pour certains algorithmes, cela pourrait être une optimisation importante à faire. Mais comme C # et VB ne génèrent pas les instructions pour ce faire, cela doit être fait manuellement (ou en utilisant F # ou un autre langage).
Voici un exemple de la façon dont la récursivité de queue peut être implémentée manuellement en C #:
Il est courant de supprimer la récursivité en déplaçant les données locales de la pile matérielle vers une structure de données de pile allouée au tas. Dans l'élimination de la récursivité des appels de queue comme indiqué ci-dessus, la pile est complètement éliminée, ce qui est une très bonne optimisation. De plus, la valeur de retour n'a pas à remonter une longue chaîne d'appels, mais elle est renvoyée directement.
Mais, de toute façon, le CIL fournit cette fonctionnalité dans le cadre du langage, mais avec C # ou VB, il doit être implémenté manuellement. (La gigue est également libre de faire cette optimisation elle-même, mais c'est un tout autre problème.)
la source
Dans MSIL, vous pouvez avoir une classe qui ne peut pas hériter de System.Object.
Exemple de code: compilez-le avec ilasm.exe MISE À JOUR: Vous devez utiliser "/ NOAUTOINHERIT" pour empêcher l'assembleur d'hériter automatiquement.
la source
TypeLoadException
). PEVerify renvoie: [MD]: Erreur: TypeDef qui n'est ni une interface ni la classe Object étend le jeton Nil.Il est possible de combiner les modificateurs d'accès
protected
etinternal
. En C #, si vous écrivezprotected internal
un membre est accessible à partir de l'assembly et des classes dérivées. Via MSIL, vous pouvez obtenir un membre accessible uniquement à partir des classes dérivées de l'assembly . (Je pense que cela pourrait être très utile!)la source
private protected
Ooh, je n'ai pas remarqué ça à l'époque. (Si vous ajoutez la balise jon-skeet, c'est plus probable, mais je ne la vérifie pas souvent.)
Il semble que vous ayez déjà de très bonnes réponses. En outre:
object
en C #, cela fonctionnera parfois. Voir une question SO uint [] / int [] pour un exemple.J'ajouterai à cela si je pense à autre chose ...
la source
<>a
comme nom en C # ...Le CLR prend déjà en charge la co / contravariance générique, mais C # n'obtient pas cette fonctionnalité avant la version 4.0
la source
En IL, vous pouvez lancer et attraper n'importe quel type, pas seulement les types dérivés de
System.Exception
.la source
try
/catch
sans parenthèses dans l'instruction catch, vous attraperez également les exceptions qui ne ressemblent pas à des exceptions. Lancer, cependant, n'est en effet possible que lorsque vous héritez deException
.IL fait la distinction entre
call
etcallvirt
pour les appels de méthode virtuelle. En utilisant le premier, vous pouvez forcer l'appel d'une méthode virtuelle du type de classe statique actuel au lieu de la fonction virtuelle dans le type de classe dynamique.C # n'a aucun moyen de faire cela:
VB, comme IL, peut émettre des appels non virtuels en utilisant la
MyClass.Method()
syntaxe. Dans ce qui précède, ce seraitMyClass.ToString()
.la source
Dans un try / catch, vous pouvez ressaisir le bloc try à partir de son propre bloc catch. Donc, vous pouvez faire ceci:
AFAIK vous ne pouvez pas faire cela en C # ou VB
la source
GOTO
Catch
à sonTry
. Exécutez le code de test en ligne ici .Avec IL et VB.NET, vous pouvez ajouter des filtres lors de la capture d'exceptions, mais C # v3 ne prend pas en charge cette fonctionnalité.
Cet exemple VB.NET est tiré de http://blogs.msdn.com/clrteam/archive/2009/02/05/catch-rethrow-and-filters-why-you-should-care.aspx (notez le
When ShouldCatch(ex) = True
dans le Clause de capture):la source
= True
, ça me fait saigner les yeux!Autant que je sache, il n'y a aucun moyen de créer des initialiseurs de module (constructeurs statiques pour un module entier) directement en C #:
http://blogs.msdn.com/junfeng/archive/2005/11/19/494914.aspx
la source
Native types
Vous pouvez travailler directement avec les types int natif et int natif non signé (en c #, vous ne pouvez travailler que sur un IntPtr qui n'est pas le même.
Transient Pointers
Vous pouvez jouer avec des pointeurs transitoires, qui sont des pointeurs vers des types gérés mais garantis de ne pas bouger en mémoire car ils ne sont pas dans le tas géré. Vous ne savez pas exactement comment vous pourriez l'utiliser utilement sans jouer avec du code non managé, mais il n'est pas exposé aux autres langages directement uniquement via des choses comme stackalloc.
<Module>
vous pouvez jouer avec la classe si vous le souhaitez (vous pouvez le faire par réflexion sans avoir besoin d'IL)
.emitbyte
.entrypoint
Vous avez un peu plus de flexibilité là-dessus, vous pouvez l'appliquer à des méthodes non appelées Main par exemple.
avoir une lecture de la spécification, je suis sûr que vous en trouverez quelques autres.
la source
<Module>
c'est une classe spéciale pour les langages qui acceptent les méthodes globales (comme le fait VB), mais en effet, C # ne peut pas y accéder directement.Vous pouvez pirater le remplacement de méthode co / contra-variance, ce que C # n'autorise pas (ce n'est PAS la même chose que la variance générique!). J'ai plus d'informations sur la mise en œuvre de ceci ici , et les parties 1 et 2
la source
Je pense que celui que je souhaitais (avec des raisons totalement erronées) était l'héritage dans Enums. Cela ne semble pas difficile à faire dans SMIL (puisque les Enums ne sont que des classes) mais ce n'est pas quelque chose que la syntaxe C # veut que vous fassiez.
la source
En voici encore plus:
la source
20) Vous pouvez traiter un tableau d'octets comme un tableau (4x plus petit) d'entiers.
Je l'ai utilisé récemment pour faire une implémentation rapide de XOR, car la fonction CLR xor fonctionne sur ints et j'avais besoin de faire XOR sur un flux d'octets.
Le code résultant s'est avéré être ~ 10x plus rapide que l'équivalent fait en C # (faisant XOR sur chaque octet).
===
Je n'ai pas assez de credz de rue stackoverflow pour modifier la question et l'ajouter à la liste en tant que # 20, si quelqu'un d'autre le pouvait, ce serait bien ;-)
la source
Quelque chose que les obfuscateurs utilisent - vous pouvez avoir un champ / une méthode / une propriété / un événement ayant tous le même nom.
la source
L'héritage enum n'est pas vraiment possible:
Vous pouvez hériter d'une classe Enum. Mais le résultat ne se comporte pas comme un Enum en particulier. Il ne se comporte même pas comme un type valeur, mais comme une classe ordinaire. La chose srange est: IsEnum: True, IsValueType: True, IsClass: False
Mais ce n'est pas particulièrement utile (sauf si vous voulez confondre une personne ou le moteur d'exécution lui-même).
la source
Vous pouvez également dériver une classe du délégué System.Multicast en IL, mais vous ne pouvez pas le faire en C #:
la source
Vous pouvez également définir des méthodes au niveau du module (aka globales) dans IL, et C #, en revanche, ne vous permet de définir des méthodes que tant qu'elles sont attachées à au moins un type.
la source