Der gesamte in .NET-Sprachen geschriebene Code wird in MSIL kompiliert. Gibt es jedoch bestimmte Aufgaben / Vorgänge, die Sie nur direkt mit MSIL ausführen können?
Lassen Sie uns auch in MSIL einfacher arbeiten als in C #, VB.NET, F #, j # oder einer anderen .NET-Sprache.
Bisher haben wir Folgendes:
- Schwanzrekursion
- Generische Co / Contravariance
- Überladungen, die sich nur in Rückgabetypen unterscheiden
- Zugriffsmodifikatoren überschreiben
- Haben Sie eine Klasse, die nicht von System.Object erben kann
- Gefilterte Ausnahmen (können in vb.net durchgeführt werden)
- Aufruf einer virtuellen Methode des aktuellen statischen Klassentyps.
- Holen Sie sich einen Überblick über die Box-Version eines Werttyps.
- Mach einen Versuch / Fehler.
- Verwendung verbotener Namen.
- Definieren Sie Ihre eigenen parameterlosen Konstruktoren für Werttypen .
- Definieren Sie Ereignisse mit einem
raise
Element. - Einige Konvertierungen sind von der CLR zulässig, jedoch nicht von C #.
- Machen Sie eine Nicht-
main()
Methode als.entrypoint
. - Arbeiten Sie direkt mit den nativen
int
und nativenunsigned int
Typen. - Spielen Sie mit vorübergehenden Zeigern
- Emitbyte-Direktive in MethodBodyItem
- Nicht System.Exception-Typen werfen und abfangen
- Enumit Enums (Unverified)
- Sie können ein Array von Bytes als (4x kleineres) Array von Ints behandeln.
- Sie können ein Feld / eine Methode / eine Eigenschaft / ein Ereignis haben, die alle denselben Namen haben (nicht überprüft).
- Sie können von einem eigenen catch-Block zurück in einen try-Block verzweigen.
- Sie haben Zugriff auf den Famandassem-Zugriffsspezifizierer (
protected internal
ist Fam oder Assem). - Direkter Zugriff auf die
<Module>
Klasse zum Definieren globaler Funktionen oder einen Modulinitialisierer.
Antworten:
MSIL ermöglicht Überladungen, die sich aufgrund nur in Rückgabetypen unterscheiden
oder
quelle
Die meisten .NET-Sprachen, einschließlich C # und VB, verwenden die Funktion zur Endrekursion von MSIL-Code nicht.
Die Schwanzrekursion ist eine Optimierung, die in funktionalen Sprachen üblich ist. Es tritt auf, wenn eine Methode A endet, indem der Wert von Methode B zurückgegeben wird, sodass der Stapel von Methode A freigegeben werden kann, sobald der Aufruf von Methode B erfolgt ist.
MSIL-Code unterstützt die Schwanzrekursion explizit, und für einige Algorithmen könnte dies eine wichtige Optimierung sein. Da C # und VB die entsprechenden Anweisungen nicht generieren, muss dies manuell erfolgen (oder mit F # oder einer anderen Sprache).
Hier ist ein Beispiel dafür, wie die Schwanzrekursion manuell in C # implementiert werden kann:
Es ist üblich, die Rekursion zu entfernen, indem die lokalen Daten vom Hardwarestapel auf eine vom Heap zugewiesene Stapeldatenstruktur verschoben werden. Bei der oben gezeigten Eliminierung der Tail-Call-Rekursion wird der Stapel vollständig eliminiert, was eine ziemlich gute Optimierung darstellt. Außerdem muss der Rückgabewert keine lange Aufrufkette durchlaufen, sondern wird direkt zurückgegeben.
Trotzdem bietet die CIL diese Funktion als Teil der Sprache an, aber mit C # oder VB muss sie manuell implementiert werden. (Der Jitter kann diese Optimierung auch selbst vornehmen, aber das ist ein ganz anderes Problem.)
quelle
In MSIL können Sie eine Klasse haben, die nicht von System.Object erben kann.
Beispielcode: Kompilieren Sie ihn mit ilasm.exe. UPDATE: Sie müssen "/ NOAUTOINHERIT" verwenden, um zu verhindern, dass Assembler automatisch erben.
quelle
TypeLoadException
). PEVerify gibt Folgendes zurück: [MD]: Fehler: TypeDef, das keine Schnittstelle und nicht die Object-Klasse ist, erweitert das Null-Token.Es ist möglich, die Modifikatoren
protected
und zu kombiniereninternal
. Wenn Sie in C # schreiben, kann aufprotected internal
ein Mitglied über die Assembly und über abgeleitete Klassen zugegriffen werden. Via MSIL können Sie ein Mitglied erhalten , die von abgeleiteten Klassen innerhalb der Baugruppe zugänglich ist nur . (Ich denke, das könnte ziemlich nützlich sein!)quelle
private protected
Oh, ich habe das damals nicht bemerkt. (Wenn Sie das Jon-Skeet-Tag hinzufügen, ist es wahrscheinlicher, aber ich überprüfe es nicht so oft.)
Es sieht so aus, als hätten Sie bereits ziemlich gute Antworten. Zusätzlich:
object
in C # übergehen, funktionieren diese manchmal. Ein Beispiel finden Sie in einer uint [] / int [] SO-Frage .Ich werde das ergänzen, wenn mir noch etwas einfällt ...
quelle
<>a
als Name in C # anzugeben ...Die CLR unterstützt bereits generische Co / Contravarianz, aber C # erhält diese Funktion erst ab 4.0
quelle
In IL können Sie jeden Typ werfen und fangen, nicht nur Typen, von denen abgeleitet wurde
System.Exception
.quelle
try
/catch
ohne Klammern in der catch-Anweisung werden auch nicht ausnahmeähnliche Ausnahmen abgefangen. Werfen ist jedoch nur möglich, wenn Sie von erbenException
.IL unterscheidet zwischen
call
undcallvirt
für virtuelle Methodenaufrufe. Mit der ersteren können Sie den Aufruf einer virtuellen Methode des aktuellen statischen Klassentyps anstelle der virtuellen Funktion im dynamischen Klassentyp erzwingen .C # hat keine Möglichkeit dazu:
VB kann wie IL mithilfe der
MyClass.Method()
Syntax nicht- virtuelle Aufrufe ausgeben . Oben wäre diesMyClass.ToString()
.quelle
In einem try / catch können Sie den try-Block von seinem eigenen catch-Block aus erneut eingeben. Sie können dies also tun:
AFAIK Sie können dies nicht in C # oder VB tun
quelle
GOTO
Catch
zu verzweigenTry
. Führen Sie hier den Testcode online aus .Mit IL und VB.NET können Sie Filter hinzufügen, wenn Ausnahmen abgefangen werden, aber C # v3 unterstützt diese Funktion nicht.
Dieses VB.NET-Beispiel stammt von http://blogs.msdn.com/clrteam/archive/2009/02/05/catch-rethrow-and-filters-why-you-should-care.aspx (beachten Sie das
When ShouldCatch(ex) = True
in der Fangklausel):quelle
= True
, es lässt meine Augen bluten!Soweit ich weiß, gibt es keine Möglichkeit, Modulinitialisierer (statische Konstruktoren für ein gesamtes Modul) direkt in C # zu erstellen:
http://blogs.msdn.com/junfeng/archive/2005/11/19/494914.aspx
quelle
Native types
Sie können direkt mit den Typen int und native int ohne Vorzeichen arbeiten (in c # können Sie nur mit einem IntPtr arbeiten, der nicht identisch ist.
Transient Pointers
Sie können mit vorübergehenden Zeigern spielen, bei denen es sich um Zeiger auf verwaltete Typen handelt, die sich jedoch garantiert nicht im Speicher bewegen, da sie sich nicht im verwalteten Heap befinden. Ich bin mir nicht ganz sicher, wie Sie dies sinnvoll nutzen können, ohne mit nicht verwaltetem Code herumzuspielen, aber es ist nicht direkt durch Dinge wie stackalloc den anderen Sprachen ausgesetzt.
<Module>
Sie können mit der Klasse herumspielen, wenn Sie dies wünschen (Sie können dies durch Nachdenken tun, ohne IL zu benötigen).
.emitbyte
.entrypoint
Sie haben etwas mehr Flexibilität, Sie können es beispielsweise auf Methoden anwenden, die nicht Main heißen.
Lesen Sie die Spezifikation. Ich bin sicher, Sie werden noch ein paar mehr finden.
quelle
<Module>
dies als spezielle Klasse für Sprachen gedacht ist, die globale Methoden akzeptieren (wie dies bei VB der Fall ist), C # jedoch nicht direkt darauf zugreifen kann.Sie können die Co / Contra-Varianz von Hack-Methoden überschreiben, was C # nicht zulässt (dies ist NICHT dasselbe wie generische Varianz!). Ich habe hier und in Teil 1 und 2 weitere Informationen zur Implementierung
quelle
Ich denke, derjenige, den ich mir immer wieder gewünscht habe (aus völlig falschen Gründen), war die Vererbung in Enums. In SMIL scheint es nicht schwierig zu sein (da Enums nur Klassen sind), aber die C # -Syntax verlangt nicht, dass Sie dies tun.
quelle
Hier noch etwas mehr:
quelle
20) Sie können ein Array von Bytes als (4x kleineres) Array von Ints behandeln.
Ich habe dies kürzlich verwendet, um eine schnelle XOR-Implementierung durchzuführen, da die CLR-xor-Funktion mit Ints arbeitet und ich XOR für einen Bytestream ausführen musste.
Der resultierende Code ist ~ 10x schneller als der in C # durchgeführte Wert (XOR für jedes Byte).
===
Ich habe nicht genug Stackoverflow Street Credz, um die Frage zu bearbeiten und diese als # 20 zur Liste hinzuzufügen, wenn jemand anderes könnte, wäre das gut ;-)
quelle
Etwas, das Verschleierer verwenden - Sie können ein Feld / eine Methode / eine Eigenschaft / ein Ereignis haben, die alle denselben Namen haben.
quelle
Enum-Vererbung ist nicht wirklich möglich:
Sie können von einer Enum-Klasse erben. Das Ergebnis verhält sich jedoch nicht wie eine Aufzählung. Es verhält sich nicht einmal wie ein Werttyp, sondern wie eine gewöhnliche Klasse. Die seltsame Sache ist: IsEnum: True, IsValueType: True, IsClass: False
Dies ist jedoch nicht besonders nützlich (es sei denn, Sie möchten eine Person oder die Laufzeit selbst verwirren.)
quelle
Sie können eine Klasse auch vom System.Multicast-Delegaten in IL ableiten, dies ist jedoch in C # nicht möglich:
quelle
Sie können in IL auch Methoden auf Modulebene (auch als globale Methoden bezeichnet) definieren, und in C # können Sie dagegen nur Methoden definieren, solange sie an mindestens einen Typ angehängt sind.
quelle