返回目录

 

     这一节只是相关于ILASM的早期版本(1.0和1.1),但是我仍然认为这是有用的信息。考虑一下这些.NET Framework版本的基本大小,你将会不止一次的遇到与这些ILASM的老版本打交道的机会。

     如果你安装了.NET Framework的早期版本,你可以对这个代码示例执行一些试验。在任意文本编辑器中打开这个源文件Simple.il并作出如下修改:将对值类型CharArray8的声明移动到字段Format的前面:

(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明{
(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
// End of namespace
(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
.class public explicit CharArray8
     (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
extends [mscorlib]System.ValueType { .size 8  }
(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
.field public static valuetype CharArray8 Format at FormatData

     事情看起来是井然有序的。但是当你试图编译这个文件时,ILAsm编译器将会失败并报出Unresolved MemberRef ‘Format’的错误信息。

     现在再次修改源文件,这次将对值类型CharArray8的声明移动到命名空间Odd.Or的前面:

(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明.class public explicit CharArray8
                    
extends [mscorlib]System.ValueType { .size 8  }
(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
.namespace Odd.or {
     (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
.class public auto ansi Even extends [mscorlib]System.Object {
          (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
.field public static int32 val
          (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
.method public staticvoid check( ) cil managed {
               (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
               (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
ldsflda valuetype CharArray8 Format
               (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
          (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
// End of method
     (翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
// End of class
(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
// End of namespace
(翻译)《Expert .NET 2.0 IL Assembler》 第一章 简单示例 1.3 类的预先声明
.field public static valuetype CharArray8 Format at FormatData

     现在,当你保存这段源代码并试图重编译它的时候,这就都回复正常了。这里面发生了什么呢?

     在第一次源代码改变后,当Format字段被check方法中的ldsflda指令引用时,值类型CharArray8还没有被声明,它的TypeRef就会因此被忽略,字段引用的签名就会收到该TypeRef作为它的类型。

     接着,值类型CharArray8被声明,一个新的TypeDef被创建。然后,当Format字段确实被声明时,它的类型被当成一个局部声明的值类型,而且该字段的签名定义接收到TypeDef作为它的类型。但是,不存在以TypeRef作为类型的名为Format的字段,被声明在模块中的任何地方。从而,你得到了引用到定义的决定性失败。

     (有一段时间批判ILAsm编译器在编程级别上缺少匹配签名的能力,伴随着类型分析和通过完全名称和决定范围来匹配TypeRef到TypeDef。然而,请耐心一些。)

     第二次改变源代码后,值类型CharArray8首次被声明——以便于所有的引用指向它,而不管这些引用在哪里出现,我们称这个类型为TypeDef。这是一个相当明显的解决方案。

     这个解决方案也会变得不明显——在你考虑两个类的时候,它们的成员互相使用对方的类型作为成员。那么先声明哪一个呢?准确地说,全部。

     在“类定义”章节我提到了类的修正技术,基于ILAsm,允许你重新打开类的范围从而声明更多类的特性和成员。解决这个声明/引用问题的基本方案是,首先为所有的类指定一个空范围类的定义。据此,你可以完全指定所有的类,包括它们的特性和成员,作为修正。“首轮”类的声明应该携带所有类标记、extends子句和implements子句,还应包括所有内嵌类(还有空范围)。你应该将所有这些成员声明维持到后期。

     这种类的预先声明的技术防止了声明/引用错误,而副作用是降低了元数据的大小,因为为了局部化定义的类而忽略多余的TypeRef是不必要的。

    (上述对ILAsm的评论,相应的解答是,编译器确实以最可能快的速度进行签名,而不需要更多高级并缓慢的方法,只要你使用到类的预先声明。)

     类的预先声明的需求,在ILAsm 2.0版本编译器中被消除了。

 

相关文章:

  • 2022-02-25
  • 2021-12-04
  • 2021-11-09
  • 2021-10-31
  • 2021-11-30
  • 2022-01-12
  • 2021-10-18
  • 2021-11-28
猜你喜欢
  • 2021-12-21
  • 2021-11-23
  • 2022-01-17
  • 2021-07-31
  • 2021-09-07
  • 2021-09-27
相关资源
相似解决方案