.NET言語で記述されたすべてのコードはMSILにコンパイルされますが、MSILを直接使用してのみ実行できる特定のタスク/操作はありますか?
また、MSILでC#、VB.NET、F#、j#、その他の.NET言語よりも簡単に処理できるようにします。
これまでのところこれがあります:
raise
要素を使用してイベントを定義します。main()
メソッドを.entrypoint
として作成します。int
およびネイティブunsigned int
型を直接操作します。protected internal
is famorassem)<Module>
クラスへの直接アクセス。MSILは、戻り値の型のみが異なるオーバーロードを許可します。
call void [mscorlib]System.Console::Write(string)
または
callvirt int32 ...
C#およびVBを含むほとんどの.Net言語は、MSILコードの末尾再帰機能を使用しません。
テール再帰は、関数型言語で一般的な最適化です。メソッドBの呼び出しが行われるとメソッドAのスタックの割り当てを解除できるように、メソッドBの値を返すことによってメソッドAが終了すると発生します。
MSILコードはテール再帰を明示的にサポートしており、一部のアルゴリズムでは、これは重要な最適化になる可能性があります。ただし、C#およびVBはこれを行うための命令を生成しないため、手動で(またはF#または他の言語を使用して)実行する必要があります。
C#で末尾再帰を手動で実装する方法の例を次に示します。
private static int RecursiveMethod(int myParameter)
{
// Body of recursive method
if (BaseCase(details))
return result;
// ...
return RecursiveMethod(modifiedParameter);
}
// Is transformed into:
private static int RecursiveMethod(int myParameter)
{
while (true)
{
// Body of recursive method
if (BaseCase(details))
return result;
// ...
myParameter = modifiedParameter;
}
}
ローカルデータをハードウェアスタックからヒープに割り当てられたスタックデータ構造に移動することにより、再帰を削除するのが一般的です。上記のような末尾呼び出しの再帰除去では、スタックが完全に除去されます。これは非常に優れた最適化です。また、戻り値は長い呼び出しチェーンをたどる必要はありませんが、直接返されます。
しかし、いずれにせよ、CILはこの機能を言語の一部として提供しますが、C#またはVBを使用すると、手動で実装する必要があります(ジッターは、この最適化を自由に行うこともできます。しかし、それはまったく別の問題です。)
MSILでは、System.Objectから継承できないクラスを持つことができます。
サンプルコード:ilasm.exeでコンパイルPDATE:アセンブラが自動継承しないようにするには、「/ NOAUTOINHERIT」を使用する必要があります。
// Metadata version: v2.0.50215
.Assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 2:0:0:0
}
.Assembly sample
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module sample.exe
// MVID: {A224F460-A049-4A03-9E71-80A36DBBBCD3}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02F20000
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit Hello
{
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Hello World!"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Hello::Main
} // end of class Hello
protected
およびinternal
アクセス修飾子を組み合わせることが可能です。 C#では、protected internal
メンバーは、アセンブリおよび派生クラスからアクセスできます。 MSILを介して、アセンブリ内の派生クラスからアクセス可能なメンバーを取得できますonly。 (私はそれがかなり役に立つかもしれないと思います!)
ああ、その時私はこれに気づかなかった。 (あなたがjon-skeetタグを追加する場合、それはより可能性が高いですが、私はそれを頻繁にチェックしません。)
あなたはすでにかなり良い答えを持っているようです。加えて:
object
を使用すると、これらが機能する場合があります。例は int []/int [] SO question を参照してください。他に何か考えたらこれに追加します...
CLRはすでに一般的な共分散をサポートしていますが、C#は4.0までこの機能を利用できません
ILでは、System.Exception
から派生したタイプだけでなく、あらゆるタイプをスローおよびキャッチできます。
ILは、仮想メソッド呼び出しについて、call
とcallvirt
を区別しています。前者を使用すると、動的クラスタイプの仮想関数の代わりに、現在の静的クラスタイプの仮想メソッドを強制的に呼び出すことができます。
C#にはこれを行う方法がありません。
_abstract class Foo {
public void F() {
Console.WriteLine(ToString()); // Always a virtual call!
}
public override string ToString() { System.Diagnostics.Debug.Assert(false); }
};
sealed class Bar : Foo {
public override string ToString() { return "I'm called!"; }
}
_
ILと同様に、VBはMyClass.Method()
構文を使用して非仮想呼び出しを発行できます。上記では、これはMyClass.ToString()
になります。
Try/catchでは、独自のcatchブロックからtryブロックに再び入ることができます。だから、これを行うことができます:
.try {
// ...
MidTry:
// ...
leave.s RestOfMethod
}
catch [mscorlib]System.Exception {
leave.s MidTry // branching back into try block!
}
RestOfMethod:
// ...
私の知る限り、C#またはVBではこれを行うことはできません
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 (Catch句のWhen ShouldCatch(ex) = True
に注意してください):
Try
Foo()
Catch ex As CustomBaseException When ShouldCatch(ex)
Console.WriteLine("Caught exception!")
End Try
私の知る限り、C#で直接モジュール初期化子(モジュール全体の静的コンストラクタ)を作成する方法はありません。
http://blogs.msdn.com/junfeng/archive/2005/11/19/494914.aspx
Native types
ネイティブintおよびネイティブunsigned int型を直接操作できます(c#では、同じではないIntPtrでのみ操作できます。
Transient Pointers
一時的なポインターを操作できます。一時的なポインターは、マネージ型へのポインターですが、マネージヒープにないため、メモリ内で移動しないことが保証されています。アンマネージコードをいじらずに、これをどのように有効に利用できるかは完全にはわかりませんが、stackallocなどの手段を通じて他の言語に直接公開されることはありません。
<Module>
必要に応じて、クラスをいじることができます(ILを必要とせずに、リフレクションによってこれを行うことができます)
.emitbyte
15.4.1.1 .emitbyteディレクティブMethodBodyItem :: =…| .emitbyte Int32このディレクティブにより、ディレクティブが出現するポイントで、符号なし8ビット値がメソッドのCILストリームに直接出力されます。 [注:.emitbyteディレクティブはテストの生成に使用されます。通常のプログラムの生成には必要ありません。エンドノート]
.entrypoint
これにはもう少し柔軟性があります。たとえば、Mainと呼ばれないメソッドに適用できます。
spec を読んでください。さらにいくつか見つけることができると思います。
ここにいくつかあります:
私がずっと望んでいたのは(完全に間違った理由で)Enumでの継承だったと思います。 (Enumsは単なるクラスであるため)SMILで行うのは難しいことではないように見えますが、C#構文で求められていることではありません。
難読化ツールが使用するもの-フィールド/メソッド/プロパティ/イベントをすべて同じ名前にすることができます。
20)バイトの配列を整数の(4倍小さい)配列として扱うことができます。
CLRのxor関数はintで動作し、バイトストリームでXORを実行する必要があったため、最近これを使用して高速のXOR実装を実行しました。
結果のコードは、C#で実行される同等のコードよりも約10倍高速であると測定されました(各バイトでXORを実行))。
===
質問を編集し、これを#20としてリストに追加するのに十分なstackoverflowストリートcredzがありません。
列挙型の継承は実際には不可能です。
Enumクラスから継承できます。ただし、結果は特にEnumのようには動作しません。値型のようにではなく、通常のクラスのように動作します。奇妙なことは:IsEnum:True、IsValueType:True、IsClass:False
しかし、それは特に便利ではありません(人またはランタイム自体を混乱させたくない場合を除きます)。
ILでSystem.Multicastデリゲートからクラスを派生させることもできますが、C#ではこれを行うことはできません。
//次のクラス定義は不正です:
パブリッククラスYourCustomDelegate:MulticastDelegate {}
ILおよびC#でモジュールレベル(別名グローバル)メソッドを定義することもできます。対照的に、少なくとも1つの型にアタッチされているメソッドのみを定義できます。