从运行时加载的程序集中获取System.Type

时间:2014-04-27 14:39:40

标签: c# .net reflection .net-assembly roslyn

作为this question的后续,我现在遇到的问题是能够获得用户在自己的解决方案中定义的类型的Type。使用标准mscorlib类型,一切正常。

问题很简单:如何从我在运行时才知道的程序集中获取此类型?

the comments here中所述:

  

另外,你是什么意思"提取类型"?你的意思是得到反射类型?没有好帮手,部分原因是(通常)你永远不能假设你正在编译的类型是在运行时创建的。 "编译时间"之间存在强烈(通常被忽视)的区别。并且"运行时间",并且很难将它们连接起来。

或者上一个问题:

  

好吧,为Type获取TypeInfo,除了命名问题之外,这是一个棘手的问题。它假设您有一个可以加载和找到的程序集。当你进行构建时,编译器可能正在加载参考程序集,这些程序集本身无法加载为" normal"组件。即使它们是,您可能必须挂钩AppDomain.AssemblyResolve来定位您的引用,以及您构建的任何程序集。

     

"生成"和"运行时"是真正不同的领域,从一个领域到另一个领域的交叉是最好的定义。我假设您确实需要System.Type,因为您正在使用其他反射API,或尝试加载该类型并从中执行代码。

我按照here列出的方法,并在我的分析器中实现了它:

private static Dictionary<string, Assembly> _assemblies = new Dictionary<string, Assembly>();

var containingAssembly = semanticModel.GetSymbolInfo(argument)
                                      .Symbol
                                      .ContainingAssembly;

if (!_assemblies.TryGetValue(containingAssembly.ToString(), out Assembly result))
{
    var newAssembly = Assembly.Load(containingAssembly.ToString());
    _assemblies.Add(containingAssembly.ToString(), newAssembly);
}

var currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += ResolveAssemblies;

private Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
    _assemblies.TryGetValue(args.Name, out Assembly result);
    return result;
}

但这并没有什么不同,我一直在

  

用户诊断分析仪&#39; DiagnosticTools.Collections.ElementaryMethodsNotOverriden.ElementaryMethodsNotOverridenAnalyzer&#39;消息引发异常&#39;无法加载文件或程序集&#39; RoslynTester,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null&#39;或其中一个依赖项。系统找不到指定的文件。&#39;。

使用fuslogvw.exe给我this log information归结为

  

日志:所有探测网址都已尝试失败。

.dll的几个子文件夹中搜索.exe/Common7/IDE/版本。

作为上下文澄清我为什么这样做:我想检查集合中使用的每种类型,并验证它是否覆盖了EqualsGetHashCode。为了确定这一点,我有一个经典的&#34;反射扩展方法,为我检查:

public static bool IsOverridden(this MethodInfo method)
{
    return method.GetBaseDefinition().DeclaringType != method.DeclaringType;
}

所以罗斯林应该有办法验证这个本身,以便我不必使用经典反射,那么这也没关系。

更新

当我使用此代码as provided by MSDN时,我得到一个&#34;无效参数&#34; Visual Studio中的异常但fuslogvw仍然显示未找到&#34;文件&#34;错误信息。造成这种差异的原因是什么?

private Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
    Assembly MyAssembly, objExecutingAssemblies;
    string strTempAssmbPath = "";

    objExecutingAssemblies = Assembly.GetExecutingAssembly();
    AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();

    foreach (AssemblyName strAssmbName in arrReferencedAssmbNames)
    {
        if (strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",")) == args.Name.Substring(0, args.Name.IndexOf(",")))
        {               
            strTempAssmbPath = @"C:\Users\Jeroen\Documents\Visual Studio 2013\Projects\RoslynTester\RoslynTester\bin\Debug\" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".exe";
            break;
        }
    }                   
    MyAssembly = Assembly.LoadFrom(strTempAssmbPath);

    return MyAssembly;
}

1 个答案:

答案 0 :(得分:2)

我假设您已经(以编程方式)找到了您的收藏中包含哪个类。你真的不需要反思来完成你想要的东西。使用Roslyn,您可以检查某个类是否使用此Equals覆盖SyntaxWalker方法:

public class FindOverrides : CSharpSyntaxWalker
{
    public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
    {
        base.VisitMethodDeclaration(node);

        if (node.Identifier.Text == "Equals" 
            && node.Modifiers.Any(m => m.Text == "override"))
        {
            // found an override of Equals()    
        }
    }
}

要(盲目地)检查给定解决方案中每种类型的每种方法,可以像这样使用:

var syntaxRoots =
    from project in solution.Projects
    from document in project.Documents
    select document.GetSyntaxRootAsync().Result;

foreach (var root in syntaxRoots)
    new FindOverrides().Visit(root);

至少有一个遗漏(如果这是一个有效的案例):我上面的代码不会发现给定类型的基类是否覆盖Equals()