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

本文关键字:集中 获取 System Type 程序集 程序 运行时 加载 | 更新日期: 2023-09-27 18:00:35

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

问题很简单:我如何从一个只有在运行时才知道的程序集中获得这种类型?

如评论所述:

还有,你说的";提取类型";?你的意思是得到反射类型?没有好的助手,部分原因是(通常)你永远不能假设你编译的类型在运行时是可创建的。";编译时";以及";运行时间";,而且很少能弥合它们。

或者在前面的问题上:

那么,为TypeInfo获取一个Type,抛开命名问题不谈,是一个棘手的问题。它假定您有一个可以加载和查找的程序集。当您进行构建时,编译器可能正在加载引用程序集,而这些引用程序集本身不能作为"加载;正常的";组件。即使是这样,您也可能需要挂接AppDomain.AssemblyResolve来定位您的引用以及您构建的任何程序集。

"构建";以及";运行时";实际上是不同的领域,从一个领域到另一个领域的交叉充其量是定义不清的。这里我假设你真的需要一个System.Type,因为你正在使用其他反射API,或者试图加载该类型并从中执行代码

我遵循了这里列出的方法,并在我的Analyzer中实现了它:

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;
}

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

用户诊断分析器"DiagnosticTools.Collections.ElementaryMethodsNotOverriden.ElementaryMethods NotOverridenAnalyzer"引发异常,消息为"无法加载文件或程序集"RoslynTester,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"或其依赖项之一。系统找不到指定的文件。'。

使用fuslogvw.exe给我这个日志信息,可以归结为

日志:所有探测URL都尝试过,但都失败了。

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

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

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

因此,如果Roslyn有办法自己验证这一点,这样我就不必使用经典反射,那么这也没问题。

更新:

当我使用MSDN提供的代码时;无效参数";在Visual Studio内部出现异常,但CCD_;找不到文件";错误消息。造成这种差异的原因是什么?

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;
}

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

我假设您已经(通过编程)发现了集合中包含的类。你并不真的需要反思来完成你想要的。使用Roslyn,您可以检查类是否使用以下SyntaxWalker:覆盖Equals方法

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()