我遇到了代码Type.GetType(myTypeName)
正在返回null
的问题,因为具有该类型的程序集不是当前正在执行的程序集。
我为此问题找到的解决方案是:
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
Type myType = assemblies.SelectMany(a => a.GetTypes())
.Single(t => t.FullName == myTypeName);
问题是第一次运行此代码会导致异常"Sequence contains no matching element"
。当我再次调用这部分代码时 - 一切正常,需要输入Type。
任何人都可以解释这种行为吗?为什么在第一次调用的范围内没有找到所需的汇编/类型?
答案 0 :(得分:3)
您遇到的问题是由AppDomain
类GetAssemblies方法的设计引起的 - 根据此方法的文档:
获取已加载到此应用程序域的执行上下文中的程序集。
因此,当你的程序类型第一次找不到时 - 它的程序集显然没有被应用程序加载。然后 - 当使用包含相关类型的程序集的某些功能时 - 已加载程序集,并且相同的代码已经可以找到缺少的类型。
请尝试直接加载程序集。而不是使用:
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
你可以使用:
List<Assembly> assemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies().Select(assembly => Assembly.LoadFrom(assembly.Name)).ToList();
答案 1 :(得分:2)
类型可能在尚未加载的程序集中。然后在你的程序中,它就是。如果你查看输出窗口,这应该让你知道何时加载程序集。
答案 2 :(得分:1)
另一个answer显示了获取Type
中可能未加载的Assembly
(在运行时)的最佳方式:
var T1 = Type.GetType("System.Web.Configuration.IAssemblyCache, " +
"System.Web, " +
"Version=4.0.0.0, " +
"Culture=neutral, " +
"PublicKeyToken=b03f5f7f11d50a3a");
正如您所看到的,遗憾的是,该方法要求您提供Type
的完整AssemblyQualifiedName,并且无法使用abbreviated forms的任何assembly name我试过了。这在某种程度上违背了我们的主要目的。如果您知道关于装配的更多细节,那么自己加载它就不会那么困难了:
var T2 = Assembly.Load("System.Web, " +
"Version=4.0.0.0, " +
"Culture=neutral, " +
"PublicKeyToken=b03f5f7f11d50a3a")
.GetType("System.Web.Configuration.IAssemblyCache");
尽管这两个示例看起来很相似,但它们执行的代码路径却截然不同;请注意,例如,后一版本在Assembly.GetType
上调用实例重载而不是静态调用Type.GetType
。因此,第二个版本可能更快或更有效。无论哪种方式,你似乎最终都在下面的CLR内部方法,并且第二个参数设置为false
,这就是为什么 这两个方法都没有遇到搜索的麻烦代表你所需的集会。
[System.Runtime.Remoting.RemotingServices]
private static RuntimeType LoadClrTypeWithPartialBindFallback (
字符串类型名称,
bool partialFallback);
从这些不便中向前迈出的一小步将是自己调用此CLR方法,但将partialFallback
参数设置为 true 。在此模式下,该函数将接受AssemblyQualifiedName
的截断版本,并在必要时定位并加载相关程序集:
static Func<String, bool, TypeInfo> LoadClrTypeWithPartialBindFallback =
typeof(RemotingServices)
.GetMethod("LoadClrTypeWithPartialBindFallback", (BindingFlags)0x28)
.CreateDelegate(typeof(Func<String, bool, TypeInfo>))
as Func<String, bool, TypeInfo>;
// ...
var T3 = LoadClrTypeWithPartialBindFallback(
"System.Web.Configuration.IAssemblyCache, System.Web",
true); // <-- enables searching for the assembly
这如图所示,并且还继续支持指定完整的AssemblyQualifiedName
,如前面的示例所示。这是一个很小的改进,但它仍然不是完全不合格的命名空间搜索,因为你仍然必须指定程序集的短名称,即使它可能是从类型名称本身中出现的命名空间推断出来的。
答案 3 :(得分:0)
如果排除mscorlib程序集? ,你可以试试这个:
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(asb=>!asb.FullName.StartsWith("mscorlib")).ToList();
Type myType = assemblies.SelectMany(a => a.GetTypes())
.Single(t => t.FullName == myTypeName);
答案 4 :(得分:0)
顺便说一句,如果你做知道包含该类型的程序集的FullName
(或者包含TypeForwardedToAttribute
类型的程序集)可以使用Type.GetType
。具体来说,Type.GetType(Assembly.CreateQualifiedName(assembly.FullName, myTypeName))
看起来像是:
Type.GetType("Some.Complete.Namespace.myTypeName, Some.Assembly.Name, Version=1.2.3.4, Culture=neutral, PublicKeyToken=ffffffffffffffff");
假设框架可以解析程序集的位置,那么将加载程序集(如果尚未加载)。
这是我的示例LinqPad查询确认了有用的TypeForwardedToAttribute
评论:
var u = (from a in AppDomain.CurrentDomain.GetAssemblies()
let t = a.GetType("System.Lazy`2")
where t != null
select t).FirstOrDefault();
(u?.AssemblyQualifiedName).Dump();
u = Type.GetType("System.Lazy`2, System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
(u?.AssemblyQualifiedName).Dump();
输出:
空
System.Lazy`2,System.ComponentModel.Composition,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089