用.NET语言编写的所有代码都编译为MSIL,但是只有使用MSIL才能直接执行特定的任务/操作吗?
让我们在MSIL中比C#,VB.NET,F#,j#或任何其他.NET语言更容易完成 .
到目前为止我们有这个:
-
尾递归
-
通用Co / Contravariance
-
重载仅在返回类型上有所不同
-
覆盖访问修饰符
-
有一个不能从System.Object继承的类
-
过滤的异常(可以在vb.net中完成)
-
调用当前静态类类型的虚方法 .
-
获取值类型的盒装版本的句柄 .
-
做一次尝试/错误 .
-
使用禁用名称 .
-
Define your own parameterless constructors for value types .
-
使用
raise
元素定义事件 . -
CLR允许一些转换,但C#不允许转换 .
-
将
main()
方法设为.entrypoint
. -
直接使用本机
int
和本机unsigned int
类型 . -
使用瞬态指针播放
MethodBodyItem中的 -
emitbyte指令
-
抛出并捕获非System.Exception类型
-
继承枚举(未验证)
-
您可以将字节数组视为(4x更小)整数数组 .
-
您可以让字段/方法/属性/事件具有相同的名称(未验证) .
-
您可以从自己的catch块分支回try块 .
-
您可以访问famandassem访问说明符(
protected internal
是fam or assem) -
直接访问
<Module>
类以定义全局函数或模块初始值设定项 .
20 回答
哦,我当时没有发现这一点 . (如果你添加jon-skeet标签更有可能,但我不经常检查它 . )
看起来你已经有了很好的答案 . 此外:
您无法处理C#中值类型的盒装版本 . 你可以在C / CLI中
你不能在C#中尝试/错误("fault"就像一个"catch everything and rethrow at the end of the block"或"finally but only on failure")
C#禁止使用许多名称但合法的IL
IL允许你define your own parameterless constructors for value types .
您无法在C#中使用"raise"元素定义事件 . (在VB中,您必须自定义事件,但"default"事件不包括一个 . )
CLR允许某些转换,但C#不允许转换 . 如果你通过C#中的
object
,这些有时会起作用 . 有关示例,请参阅uint[]/int[] SO question .如果我想到别的什么,我会加上这个......
MSIL允许重载仅因返回类型而异
要么
大多数.Net语言(包括C#和VB)都不使用MSIL代码的尾递归功能 .
尾递归是一种在函数式语言中很常见的优化 . 它发生在方法A通过返回方法B的值而结束时,一旦调用方法B,就可以释放方法A的堆栈 .
MSIL代码显式支持尾递归,对于某些算法,这可能是一个重要的优化 . 但由于C#和VB不生成执行此操作的指令,因此必须手动完成(或使用F#或其他语言) .
下面是一个如何在C#中手动实现尾递归的示例:
通常的做法是通过将本地数据从硬件堆栈移动到堆分配的堆栈数据结构来删除递归 . 在如上所示的尾调用递归消除中,完全消除了堆栈,这是一个非常好的优化 . 此外,返回值不必走长调用链,但直接返回 .
但是,无论如何,CIL提供此功能作为语言的一部分,但使用C#或VB,它必须手动实现 . (抖动也可以自由地进行优化,但这是另一个问题 . )
在MSIL中,您可以拥有一个不能从System.Object继承的类 .
示例代码:使用ilasm.exe编译它 UPDATE: 必须使用"/NOAUTOINHERIT"来防止汇编程序自动继承 .
可以组合
protected
和internal
访问修饰符 . 在C#中,如果编写protected internal
,则可以从程序集和派生类访问成员 . 通过MSIL,您可以获得一个只能从程序集中的派生类访问的成员 . (我认为这可能非常有用!)CLR已经支持通用协同/反演,但C#直到4.0才获得此功能
C# 4.0 Features
Co/Contravariance
在IL中,您可以抛出并捕获任何类型,而不仅仅是从
System.Exception
派生的类型 .对于虚方法调用,IL具有
call
和callvirt
之间的区别 . 通过使用前者,您可以强制调用当前静态类类型的虚方法,而不是动态类类型中的虚函数 .C#无法做到这一点:
与IL一样,VB可以使用
MyClass.Method()
语法发出非虚拟调用 . 在上面,这将是MyClass.ToString()
.在try / catch中,您可以从其自己的catch块重新输入try块 . 所以,你可以这样做:
AFAIK你不能用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 ):
据我所知,没有办法直接在C#中创建模块初始化器(整个模块的静态构造函数):
http://blogs.msdn.com/junfeng/archive/2005/11/19/494914.aspx
Native types
您可以直接使用native int和native unsigned int类型(在c#中,您只能使用不同的IntPtr .
Transient Pointers
您可以使用瞬时指针,它是指向托管类型的指针,但保证不会在内存中移动,因为它们不在托管堆中 . 不完全确定如何在不弄乱非托管代码的情况下如何有效地使用它,但它不会直接通过stackalloc之类的东西直接暴露给其他语言 .
<Module>
如果你愿意的话,你可以搞乱这个课程(你可以通过反思来做到这一点而不需要IL)
.emitbyte
.entrypoint
您可以在此方面获得更多灵活性,例如,您可以将其应用于未称为Main的方法 .
读了一下spec我发现了一些 .
你可以破解方法覆盖co / contra-variance,C#没有更多关于实现这个here的信息,以及部分1和2
我认为我一直希望的(完全错误的原因)是Enums中的继承 . 在SMIL中做起来似乎并不困难(因为Enums只是类),但它不是C#语法要求你做的事情 .
这里还有一些:
您可以在委托中使用额外的实例方法 .
代理可以实现接口 .
您可以在委托和接口中拥有静态成员 .
20)您可以将一个字节数组视为(4x更小)整数数组 .
我最近使用它来执行快速XOR实现,因为CLR xor函数在int上运行,我需要在字节流上进行XOR .
测得的结果代码比C#中的等效代码快10倍(在每个字节上进行异或) .
===
我没有足够的stackoverflow street credz来编辑问题并将其添加到列表中作为#20,如果其他人可能会膨胀;-)
混淆器使用的东西 - 你可以让一个字段/方法/属性/事件具有相同的名称 .
枚举继承是不可能的:
您可以从Enum类继承 . 但结果并不像Enum那样特别 . 它的行为甚至不像值类型,而是像普通的类一样 . srange是:IsEnum:True,IsValueType:True,IsClass:False
但这并不是特别有用(除非你想混淆一个人或运行时本身 . )
您还可以从IL中的System.Multicast委托派生一个类,但是您不能在C#中执行此操作:
您还可以在IL中定义模块级(也称为全局)方法,而C#只允许您定义方法,只要它们附加到至少一种类型即可 .