本文提供了此 API 参考文档的补充说明。
利用GetType(String, Func<AssemblyName,Assembly>, Func<Assembly,String,Boolean,Type>, Boolean, Boolean)方法重载及其关联的重载(GetType(String, Func<AssemblyName,Assembly>, Func<Assembly,String,Boolean,Type>)和GetType(String, Func<AssemblyName,Assembly>, Func<Assembly,String,Boolean,Type>, Boolean))将GetType方法的默认实现替换为更加灵活的实现。 通过提供自己的方法来解析类型名称和包含它们的程序集的名称,可以执行以下操作:
- 控制从中加载类型的程序集的版本。
- 提供另一个位置来查找不包含程序集名称的类型名称。
- 使用部分程序集名称加载程序集。
- 返回公共语言运行时(CLR)未创建的子类 System.Type 。
例如,在版本容错序列化中,此方法允许使用部分名称搜索“最适合”程序集。 GetType 方法的其他重载需要程序集限定的类型名称,其中包括版本号。
类型系统的备用实现可能需要返回 CLR 未创建的子类 System.Type ;该方法的其他重载 GetType 返回的所有类型都是运行时类型。
使用注意事项
此重载方法及其相关的重载方法将 typeName 解析为类型名称和程序集名称,然后进行解析。 程序集名称的解析发生在类型名称解析之前,因为必须在程序集的上下文中解析类型名称。
注释
如果不熟悉程序集限定类型名称的概念,请参阅 AssemblyQualifiedName 属性。
如果 typeName 不是程序集限定的名称,则跳过程序集解析。 可以在 mscorlib.dll/System.Private.CoreLib.dll 或当前正在执行的程序集的上下文中解析非限定类型名称,或者可以选择在 typeResolver 参数中提供程序集。 在 混合名称解析 部分中,包括或省略不同类型名称解析的程序集名称的效果显示为表。
常规用法说明:
不要将未知或不受信任的调用方的方法传递给
assemblyResolver或typeResolver。 仅使用你提供或熟悉的方法。谨慎
使用未知或不受信任的调用方的方法可能会导致恶意代码特权提升。
如果省略
assemblyResolver和/或typeResolver参数,则参数的值throwOnError将传递给执行默认解析的方法。如果
throwOnError是true,当TypeLoadException返回typeResolver时,此方法将引发null;当FileNotFoundException返回assemblyResolver时,将引发null。此方法不捕获由
assemblyResolver和typeResolver引发的异常。 你负责解析器方法引发的任何异常。
解析程序集
该方法 assemblyResolver 接收一个 AssemblyName 对象,该对象是通过分析包含在 typeName其中的字符串程序集名称生成的。 如果 typeName 不包含程序集名称, assemblyResolver 则不调用并 null 传递给 typeResolver。
如果assemblyResolver未被提供,则使用标准程序集探测机制来查找程序集。 如果 assemblyResolver 已提供,GetType 方法则不会执行标准探测,此时必须确保 assemblyResolver 可处理传递给它的所有程序集。
如果无法解析程序集,该方法 assemblyResolver 应返回 null 。 如果assemblyResolver返回null,则不会调用typeResolver,且不会发生进一步的处理;此外,如果throwOnError是true,则会引发FileNotFoundException。
AssemblyName如果传递给assemblyResolver的是部分名称,则其一个或多个部分为 null。 例如,如果它没有版本,则 Version 属性为 null. 如果Version属性、CultureInfo属性和GetPublicKeyToken方法全部返回null,那么仅提供了程序集的简单名称。 该方法 assemblyResolver 可以使用或忽略程序集名称的所有部分。
不同的程序集解析选项的效果显示在 混合名称解析 部分中的表格中,适用于简单类型名称和程序集限定的类型名称。
解析类型
如果 typeName 未指定程序集名称,则始终调用 typeResolver。 如果 typeName 指定程序集名称, typeResolver 则仅在成功解析程序集名称时调用。 如果 assemblyResolver 或标准程序集探测返回 null, typeResolver 则不调用。
该方法 typeResolver 接收三个参数:
- 要搜索的程序集,或者如果
null不包含程序集名称,则为typeName。 - 类型的简单名称。 对于嵌套类型,这是最外部的包含类型。 对于泛型类型,这是泛型类型的简单名称。
- 一个布尔值,如果忽略类型名称的大小写则为
true。
实现确定使用这些参数的方式。
typeResolver如果方法无法解析类型,则该方法应返回null。 如果typeResolver返回null且throwOnError为true,则GetType的此重载将引发TypeLoadException。
对于简单和程序集限定的类型名称,不同类型解析选项的效果会显示为混合名称解析部分中的表。
解析嵌套类型
如果 typeName 为嵌套类型,则仅将最外层包含类型的名称传递给 typeResolver。 当typeResolver返回此类型时,GetNestedType方法以递归方式调用,直到最内部的嵌套类型被解析。
解析泛型类型
以 GetType 递归方式调用它以解析泛型类型:首先解析泛型类型本身,然后解析其类型参数。 如果类型参数是泛型的, GetType 则以递归方式调用以解析其类型参数,依此类推。
你提供的组合assemblyResolvertypeResolver必须能够解析此递归的所有级别。 例如,假设提供一个用于控制 assemblyResolver 加载的 MyAssembly。 假设你想要解析泛型类型 Dictionary<string, MyType> (Dictionary(Of String, MyType) 在 Visual Basic 中)。 可能会传递以下泛型类型名称:
"System.Collections.Generic.Dictionary`2[System.String,[MyNamespace.MyType, MyAssembly]]"
请注意, MyType 这是唯一的程序集限定类型参数。
Dictionary<TKey,TValue> 与 String 类的名称都不是程序集限定的。
typeResolver 必须能处理程序集或 null,因为它将为 null 和 Dictionary<TKey,TValue> 接收 String。 它可以通过调用一个接受字符串作为参数的 GetType 方法重载来处理这种情况,因为两个未限定的类型名称都位于 mscorlib.dll/System.Private.CoreLib.dll中。
Type t = Type.GetType(test,
(aName) => aName.Name == "MyAssembly" ?
Assembly.LoadFrom(@".\MyPath\v5.0\MyAssembly.dll") : null,
(assem, name, ignore) => assem == null ?
Type.GetType(name, false, ignore) :
assem.GetType(name, false, ignore)
);
let t =
Type.GetType(test,
(fun aName ->
if aName.Name = "MyAssembly" then
Assembly.LoadFrom @".\MyPath\v5.0\MyAssembly.dll"
else null),
fun assem name ignr ->
if assem = null then
Type.GetType(name, false, ignr)
else
assem.GetType(name, false, ignr))
不会为字典类型和字符串类型调用assemblyResolver方法,因为这些类型名称不是程序集限定的。
现在假设不是System.String,而是YourType作为第一个泛型参数类型,来自YourAssembly:
"System.Collections.Generic.Dictionary`2[[YourNamespace.YourType, YourAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null], [MyNamespace.MyType, MyAssembly]]"
由于此程序集既不是 mscorlib.dll/System.Private.CoreLib.dll,也不是当前正在执行的程序集,因此不能在没有程序集限定名称的情况下解析 YourType 。
assemblyResolve 将以递归方式被调用,因此它必须能够处理这种情况。 现在,它使用提供的null对象来执行程序集加载,而不是为不同于MyAssembly的程序集返回AssemblyName。
Type t2 = Type.GetType(test,
(aName) => aName.Name == "MyAssembly" ?
Assembly.LoadFrom(@".\MyPath\v5.0\MyAssembly.dll") :
Assembly.Load(aName),
(assem, name, ignore) => assem == null ?
Type.GetType(name, false, ignore) :
assem.GetType(name, false, ignore), true
);
let t2 =
Type.GetType(test,
(fun aName ->
if aName.Name = "MyAssembly" then
Assembly.LoadFrom @".\MyPath\v5.0\MyAssembly.dll"
else Assembly.Load aName),
(fun assem name ignr ->
if assem = null then
Type.GetType(name, false, ignr)
else
assem.GetType(name, false, ignr)), true)
解析具有特殊字符的类型名称
某些字符在程序集限定名称中具有特殊含义。 如果简单类型名称包含这些字符,则当简单名称是程序集限定名称的一部分时,这些字符会导致分析错误。 若要避免分析错误,必须使用反斜杠转义特殊字符,然后才能将程序集限定名称传递给 GetType 方法。 例如,如果一个类型被命名为Strange]Type,则必须在方括号之前添加转义字符,如下所示:Strange\]Type
注释
不能在 Visual Basic 或 C# 中创建具有此类特殊字符的名称,但可以使用公共中间语言(CIL)或发出动态程序集来创建。
下表显示了类型名称的特殊字符。
| 字符 | 含义 |
|---|---|
, (逗号) |
程序集限定名称的分隔符。 |
[] (方括号) |
作为后缀对,指示数组类型;作为分隔符对,将泛型参数列表和程序集限定的名称括起来。 |
&(与号) |
指示类型为引用类型的后缀。 |
* (星号) |
指示类型为指针类型的后缀。 |
+(加号) |
嵌套类型的分隔符。 |
\ (反斜杠) |
转义字符。 |
AssemblyQualifiedName 等属性会返回正确转义的字符串。 必须将正确转义的字符串传递给 GetType 方法。 反过来,GetType 方法会将正确转义的名称传递给 typeResolver 以及默认类型解析方法。 如果需将名称与 typeResolver 中的未转义名称进行比较,则必须删除转义字符。
混合名称解析
下表汇总了在assemblyResolver、typeResolver 和默认名称解析之间针对 typeName 中类型名称与程序集名称的所有组合的交互。
| 类型名称的内容 | 程序集解析程序方法 | 类型解析程序方法 | 结果 |
|---|---|---|---|
| 类型、组装 | Null | Null | 等效于调用 Type.GetType(String, Boolean, Boolean) 方法重载。 |
| 类型、组装 | 已提供 | Null |
assemblyResolver 返回程序集,否则在无法解析程序集时返回 null。 如果解析程序集,则 Assembly.GetType(String, Boolean, Boolean) 方法重载用于从程序集加载类型;否则,不会尝试解析该类型。 |
| 类型、组装 | Null | 已提供 | 等效于将程序集名称转换为对象 AssemblyName 并调用 Assembly.Load(AssemblyName) 方法重载来获取程序集。 如果程序集已解析,则会传递给 typeResolver;否则,不会调用 typeResolver,并且不会进一步尝试解析该类型。 |
| 类型、组装 | 已提供 | 已提供 |
assemblyResolver 返回程序集,否则在无法解析程序集时返回 null。 如果程序集已解析,则会传递给 typeResolver;否则,不会调用 typeResolver,并且不会进一步尝试解析该类型。 |
| 类型 | null,已提供 | Null | 等效于调用 Type.GetType(String, Boolean, Boolean) 方法重载。 由于未提供程序集名称,因此只搜索 mscorlib.dll/System.Private.CoreLib.dll 和当前正在执行的程序集。 如果 assemblyResolver 已提供,则忽略它。 |
| 类型 | null,已提供 | 已提供 |
typeResolver 被调用,并且 null 被传递给程序集。
typeResolver 可以从任何程序集提供类型,包括它为此加载的程序集。 如果 assemblyResolver 已提供,则忽略它。 |
| 集会 | null,已提供 | null,已提供 | 抛出 FileLoadException,因为程序集名称被解析得似乎是程序集限定的类型名称。 这会导致程序集名称无效。 |