从运行时加载的程序集中获取 System.Type [英] Getting the System.Type from an assembly loaded at runtime

查看:21
本文介绍了从运行时加载的程序集中获取 System.Type的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

As a followup to this question I have now come to the problem of being able to get the Type of a type that is defined by the user in his own solution. Using the standard mscorlib types, everything works.

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

The question is very easy: how can I get this type from an assembly that I will only know at runtime?

此处的评论中所述:

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

Also, what do you mean by "extracting the type"? You mean getting the Reflection type? There's no good helper, partly because (typically) you can never assume the type you're compiling against is creatable at runtime. There's a strong (and often overlooked) distinction between "compile time" and "run time", and it's rare to bridge them.

或者这里是上一个问题:

Or here on the previous question:

好吧,所以为 TypeInfo 获取一个 Type,撇开命名问题不谈,是一个棘手的问题.它假设您有一个可以加载和找到的程序集.当您进行构建时,编译器可能正在加载本身无法作为正常"加载的引用程序集.组件.即使是这样,您也可能需要挂钩 AppDomain.AssemblyResolve 来定位您的引用以及您构建的任何程序集.

Well, so getting a Type for TypeInfo, naming issues aside, is a tricky problem. It assumes you have an assembly that can be loaded and found. When you do a build, the compiler might be loading reference assemblies that themselves can't be loaded as "normal" assemblies. Even if they are, you might have to hook AppDomain.AssemblyResolve to locate your references, and whatever assembly you built.

构建"和运行时"是真正不同的域,从一个域到另一个域的定义充其量是不明确的.我在这里假设您确实需要 System.Type,因为您正在使用其他一些反射 API,或者尝试加载该类型并从中执行代码.

"Build" and "runtime" are really different domains, and crossing from one to the other is poorly defined, at best. I assume here that you really need a System.Type because you're using some other reflection API, or trying to then load that type and execute code from it.

我遵循了此处的方法,并在我的分析器:

I have followed the approach as laid out here and implemented it as such in my 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;
}

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

But this hasn't made a difference, I keep getting

用户诊断分析器DiagnosticTools.Collections.ElementaryMethodsNotOverriden.ElementaryMethodsNotOverridenAnalyzer"抛出异常并显示消息无法加载文件或程序集"RoslynTester,版本=1.0.0.0,Culture=neutral,PublicKeyToken=null"或其依赖项之一.系统找不到指定的文件.'.

The User Diagnostic Analyzer 'DiagnosticTools.Collections.ElementaryMethodsNotOverriden.ElementaryMethodsNotOverridenAnalyzer' threw an exception with message 'Could not load file or assembly 'RoslynTester, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.'.

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

Using fuslogvw.exe gives me this log information which boils down to

LOG:所有探测 URL 都尝试并失败.

LOG: All probing URLs attempted and failed.

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

After searching for the .dll and .exe version in a few subfolders of /Common7/IDE/.

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

As context to clarify why I'm doing this: I want to check every type that is used in a collection and verify that it overrides both Equals and GetHashCode. To determine this I have a "classic" reflection extension method that checks this for me:

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

因此,如果 Roslyn 有一种方法可以验证这一点,从而使我完全不必使用经典反射,那么这也很好.

So should Roslyn have a way to verify this itself that would make it so that I don't have to use classic reflection at all, then this would also be fine.

更新:

当我使用此代码由 MSDN 提供时,我得到一个;无效参数"Visual Studio 中的异常,但 fuslogvw 仍然显示找不到文件"错误信息.造成这种差异的原因是什么?

When I use this code as provided by MSDN, I get an "invalid parameter" exception inside Visual Studio but fuslogvw still shows a "file not found" error message. What causes this discrepancy?

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:UsersJeroenDocumentsVisual Studio 2013ProjectsRoslynTesterRoslynTesterinDebug" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".exe";
            break;
        }
    }                   
    MyAssembly = Assembly.LoadFrom(strTempAssmbPath);
    
    return MyAssembly;
}

推荐答案

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

I'm assuming you've already found out (programmatically) which class are contained in your collection. You don't really need reflection to accomplish what you want. With Roslyn you can check if a class overrides the Equals method with this 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()    
        }
    }
}

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

To (blindly) check every method of every type in a given solution it can be used like this:

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

There is at least one omission (if that's a valid case for you): my code above won't find if a base class of a given type is overriding Equals().

这篇关于从运行时加载的程序集中获取 System.Type的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆