6

我遇到了代码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"。当我再次调用这部分代码时 - 一切正常并且加载了所需的类型。

谁能解释这种行为?为什么在第一次调用的范围内没有找到需要的程序集/类型?

4

5 回答 5

4

您面临的问题是由类的GetAssemblies方法的设计引起的AppDomain- 根据文档,此方法:

获取已加载到此应用程序域的执行上下文中的程序集。

因此,当您的程序类型第一次找不到时 - 它的程序集显然还没有被应用程序加载。之后 - 当使用了包含相关类型的程序集的某些功能时 - 程序集已经加载,并且相同的代码已经可以找到丢失的类型。

请尝试直接加载程序集。而不是使用:

var assemblies = AppDomain.CurrentDomain.GetAssemblies();

您可以使用:

List<Assembly> assemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies().Select(assembly => Assembly.LoadFrom(assembly.Name)).ToList();
于 2012-09-14T11:07:54.367 回答
2

该类型可能位于尚未加载的程序集中。稍后在您的程序中它是。如果您查看输出窗口,这应该可以让您了解何时加载程序集。

于 2012-09-14T10:34:25.510 回答
1

另一个答案显示了获取(在运行时)可能未加载的Type定义的最佳方法:Assembly

var T1 = Type.GetType("System.Web.Configuration.IAssemblyCache, " + 
                      "System.Web, " + 
                      "Version=4.0.0.0, " + 
                      "Culture=neutral, " + 
                      "PublicKeyToken=b03f5f7f11d50a3a");

如您所见,不幸的是,该方法要求您提供完整的AssemblyQualifiedNameType并且不适用于我尝试过的任何程序集名称的缩写形式。这在某种程度上违背了我们在这里的主要目的。如果您知道有关程序集的很多细节,那么自己加载它就不会那么困难了:

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]
私有静态 RuntimeType LoadClrTypeWithPartialBindFallback (
                  String typeName,
                  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在前面的示例中指定完整。这是一个小的改进,但它仍然不是完全不合格的命名空间搜索,因为您仍然必须指定程序集的短名称,即使它可能是从出现在类型名称本身中的命名空间推导出来的。

于 2017-05-25T00:24:30.887 回答
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);
于 2012-09-14T11:06:36.870 回答
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();

输出:

null
System.Lazy`2,System.ComponentModel.Composition,版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089

于 2016-09-14T11:47:33.323 回答