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

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

问题描述

作为后续到这个问题我现在已经来到了能够获得<$ C $问题C>键入由他自己的解决方案,用户定义的类型。使用标准的的mscorlib 类型的,一切正常。

现在的问题是很容易的:我怎么能得到这个类型从一个程序集,我只知道在运行时

作为<一个描述href="http://stackoverflow.com/questions/23247521/get-type-information-for-type-declared-in-another-assembly-project">the这里评论:

  

另外,你所说的提取类型是什么意思?你的意思是让反射式?有没有好帮手,一方面是因为(典型值),你不能假设你对编译的类型是可创建在运行时。有编译时和运行时间之间有很强的(而且常常被忽视)的区别,这是罕见的填补他们。

还是这里的previous问题:

  

好了,就得到一个键入所属类别,命名问题放在一边,是一个棘手的问题。它假定你有一个可以加载和发现的组件。当你做一个构建,编译器可能会加载一个自己无法加载为正常的程序集的引用程序集。即使是这样,你可能要挂钩 AppDomain.AssemblyResolve 来找到你的推荐,不管你组装建造。

     

构建和运行真的是不同的领域,从一个到另一个路口被定义不清,充其量。我这里假设你真的需要一个System.Type的,因为你使用的是其他一些反射API,或者试图然后加载类型,然后从它执行code。

我按照所制订的办法<一href="http://stackoverflow.com/questions/9180638/working-with-appdomain-assemblyresolve-event">here并实现了它象这样在我的分析:

 私有静态字典&LT;字符串,大会&GT; _assemblies =新字典&LT;字符串,装配及GT;();

VAR containingAssembly = semanticModel.GetSymbolInfo(参数)
                                      。符号
                                      .ContainingAssembly;

如果(!_assemblies.TryGetValue(containingAssembly.ToString(),从大会结果))
{
    变种newAssembly =的Assembly.Load(containingAssembly.ToString());
    _assemblies.Add(containingAssembly.ToString(),newAssembly);
}

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

私人大会ResolveAssemblies(对象发件人,ResolveEventArgs参数)
{
    _assemblies.TryGetValue(args.Name,出大会结果);
    返回结果;
}
 

但是,这并没有做出区别,我不断收到

  

用户诊断分析仪DiagnosticTools.Collections.ElementaryMethodsNotOverriden.ElementaryMethodsNotOverridenAnalyzer有消息引发了异常无法加载文件或程序集RoslynTester,版本= 1.0.0.0,文化=中性公钥=空'或一个依赖。该系统找不到指定的文件。

使用 fuslogvw.exe 给我此日志信息它归结为

  

日志:所有探测网址企图失败

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

随着上下文来解释,为什么我这样做:我要检查所使用的收集和核实每一个类型,它会覆盖等于 GetHash code 。为了确定这一点,我有一个检查这对我来说是经典反射扩展方法:

 公共静态布尔IsOverridden(此MethodInfo的方法)
{
    返回method.GetBaseDefinition()DeclaringType = method.DeclaringType!;
}
 

所以应该罗斯林有一种方法来验证这本身就使这样我就不必使用传统的反思的话,那么这也将是罚款。

更新:

当我使用这个$ C $通过MSDN 为提供的C ,我得到一个无效的参数异常在Visual Studio中,但 fuslogvw 仍显示找不到文件的错误消息。是什么原因导致这种差异?

 私人大会ResolveAssemblies(对象发件人,ResolveEventArgs参数)
{
    大会MyAssembly程序,objExecutingAssemblies;
    字符串strTempAssmbPath =;

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

    的foreach(的AssemblyName strAssmbName在arrReferencedAssmbNames)
    {
        如果(strAssmbName.FullName.Substring(0,strAssmbName.FullName.IndexOf(,))== args.Name.Substring(0,args.Name.IndexOf(,)))
        {
            strTempAssmbPath = @C:\用户\吉荣\文档\ Visual Studio的2013 \项目\ RoslynTester \ RoslynTester \斌\调试\+ args.Name.Substring(0,args.Name.IndexOf())+ 。EXE文件;
            打破;
        }
    }
    MyAssembly程序= Assembly.LoadFrom(strTempAssmbPath);

    返回MyAssembly程序;
}
 

解决方案

我假设你已经发现了(编程)的类都包含在您的收藏。你并不真正需要的反射来完成你想要的。随着罗斯林,你可以检查一个类覆盖了等于方法,这个 SyntaxWalker

 公共类FindOverrides:CSharpSyntaxWalker
{
    公众覆盖无效VisitMethodDeclaration(MethodDeclarationSyntax节点)
    {
        base.VisitMethodDeclaration(节点);

        如果(node.Identifier.Text ==等于
            &功放;&安培; node.Modifiers.Any(M =&GT; m.Text ==覆盖))
        {
            //发现的Equals的重写()
        }
    }
}
 

要(盲目)检查每个类型的方法,在给定的解决方案,它可以是这样的:

  VAR syntaxRoots =
    从solution.Projects项目
    从project.Documents文件
    选择document.GetSyntaxRootAsync()结果。

的foreach(在syntaxRoots VAR根)
    新FindOverrides()访问(根)。
 

至少有一疏漏(如果这是对你有效的情况下):我的code以上不会发现,如果给定类型的基类中重写等于()

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?

As described in the comments here:

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:

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.

"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

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.'.

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

LOG: All probing URLs attempted and failed.

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

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

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.

Update:

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

解决方案

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

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天全站免登陆