CLR如何解析引用的类型
CLR寻找类型只有三种可能地方
- 相同文件(相同程序集)
- 不同文件, 相同程序集
- 不同文件, 不同程序集
相同文件
案例一:
以下案例是执行Point_1.exe时, 运行到statement ①时, CLR寻
找Point类型在相同的程序集中相同模块文件Point_1.exe的情形
- 源程序:
/* File: Point.cs*/
public class Program {
public static void Main() {
System.Console.WriteLine(new Point(){ x = 1, y = 2});// statement ①
}
}
public class Point
{
public int x { set; get; }
public int y { set; get; }
public override string ToString() { return $"Point({this.x}, {this.y})"}
}
- 编译:
...> csc Point.cs /out:Point_1.exe
- 执行:
...> Point_1.exe // Output: Point(1, 2)
案例二:
以下案例虽然类型Point被定义在不同的C#源文件中, 但编译时生成
一个单文件程序集Point_2.exe. 该案例用来说明这种情况仍然是情
形一, 即相同文件指的是相同程序集的相同模块文件
- 源文件
/* File: Main_Point.cs */
public class Program {
public static void Main() {
System.Console.WriteLine(new Point(){ x = 1, y = 2});
}
}
/* File: Point.cs */
public class Point
{
public int x { set; get; }
public int y { set; get; }
public override string ToString() { return $"Point({this.x}, {this.y})"; }
}
- 编译
...> csc Point.cs Main_Point.cs /out:Point_2.exe
- 运行
...> Point_2.exe // Output: Point(1, 2)
目录结构
不同文件, 相同程序集
案例三:
以下案例将实现了乘法功能的源码MultiplyUtility.cs编译成一个必须依附其它Managed Module的
Module即MultiplyUtility.netmodule, 然后将Program.cs编译成一个Assembly Manifest
宿主Managed Module. 至此, 一个Multifile Assembly产生, 它由两个File构成.
- 源码
- 编译(成多文件程序集)
...> csc /t:module MultiplyUtility.cs // file generated: MultiplyUtility.netmodule
...> csc /t:exe /addmodule:MultiplyUtility.netmodule Program.cs // file generated: Program.exe
注: 此时程序集为多文件程序集, 结构如下
- 运行
...> Program.exe
10
20
200
不同文件, 不同程序集
案例四:
注: 如果CLR类型搜索时, 发现它在另一个程序集, 那么CLR loads 包含Referenced Assembly's Manifest的File,
Reference Assembly可能是多文件程序集, 所以Referenced Type可能在Referenced Assembly的Main Managed Module
file中, 亦可能在其他模块文件中.
- 源码(与 "不同文件, 相同程序集"一样)
- 编译(成多个程序集)
...> csc /t:library /out:Multiply.dll MultiplyUtility.cs // file generated: Multiply.dll
...> csc /t:exe /out:Program.exe /reference:Multiply.dll Program.cs // file generated: Program.exe
- 运行((与 "不同文件, 相同程序集"一样)
...> Program.exe
10
20
200
案例五:
程序集"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"是.NET Framework中核心
的程序集之一. 执行到Statement ②时, Resolve Type - Console 时, 需要Load上一句提到的Assembly中Module File -
MSCorLib.dll
- 代码
public class Program {
public static void Main() {
System.Console.WriteLine("Ni Hao!");// Statement ②
}
}
- 编译
...> csc /out:Program.exe /r:MSCorLib.dll Program.cs
- 执行
...> Program.exe
Ni Hao!
Early Binding versus Late Binding
Early Binding(Static Binding)
早期绑定是 During Compile Time 就确定应用程序要使用的类型和方法
以上的所有案例均是 Early Binding
Late Binding(Dynamic Binding)
During Compile Time, Compiler 不知道变量是什么类型的对象以及它所持有的方法或属性是什么,这
里的对象被称为Dynamic Object, 而该对象的具体类型取决于右侧数据 DuringRun Time. 这种情况就
是晚期绑定.
案例六:
以下案例与案例三一样实现对输入数据执行乘法运算的功能. 该案例是在Run Time, 通过Reflection机制
Load Assembly, 绑定obj到另一个程序集的Type - Myclass并调用Multiply方法.
- 源程序
注: 以下为源程序文件图片
注: 以下为源程序, 与图片内容无区别, 方便复制
// 3. *不同程序集, 不同文件*, 利用反射在运行时加载程序集
// The Assembly Manifest Module - Program.exe. It's AssemblyRef MetaData Table doesn't have Assembly Reference Entry about Multiply
// File: Program.cs
using System.Reflection;
using System;
public class Program {
public static void Main() {
int a = int.Parse(System.Console.ReadLine());
int b = int.Parse(System.Console.ReadLine());
Type tp = Assembly
.LoadFile(@"C:\Users\Administrator\Desktop\abcdef\Multiply.dll") // 引用类型所在程序集的所在模块文件
.GetType("MyClass");
object obj = Activator.CreateInstance(tp);//实例化
MethodInfo meth = tp.GetMethod("Multiply");//加载方法
int? res = meth.Invoke(obj, new Object[] {a, b}) as int?;//执行
System.Console.WriteLine(res.Value);
System.Console.ReadKey();
}
}
/* MultiplyUtility.cs */
public class MyClass
{
public static int Multiply(int a, int b){
return a * b;
}
}
- 编译(成两个程序集)
...> csc /t:library /out:Multiply.dll MultiplyUtility.cs
...> csc /t:exe /out:Program.exe Program.cs
- 执行
...> Program.exe
10
20
200