本文提供了此 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 则以递归方式调用以解析其类型参数,依此类推。
你提供的组合assemblyResolver
typeResolver
必须能够解析此递归的所有级别。 例如,假设提供一个用于控制 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,因为程序集名称被解析得似乎是程序集限定的类型名称。 这会导致程序集名称无效。 |