【发布时间】:2014-04-27 14:39:40
【问题描述】:
作为this question 的后续行动,我现在遇到的问题是能够获得用户在自己的解决方案中定义的类型的Type。使用标准的 mscorlib 类型,一切正常。
这个问题很简单:我怎样才能从我只会在运行时知道的程序集中获得这种类型?
如the comments here中所述:
另外,“提取类型”是什么意思?你的意思是得到反射类型?没有好帮手,部分原因是(通常)你永远不能假设你正在编译的类型在运行时是可创建的。 “编译时”和“运行时”之间有很强的(但经常被忽视的)区别,很少能将它们联系起来。
或者这里关于上一个问题:
好吧,所以为
TypeInfo获得一个Type,除了命名问题之外,这是一个棘手的问题。它假定您有一个可以加载和找到的程序集。当您进行构建时,编译器可能正在加载本身不能作为“正常”程序集加载的引用程序集。即使它们是,您也可能需要挂钩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;
}
但这并没有什么不同,我不断得到
用户诊断分析器“DiagnosticTools.Collections.ElementaryMethodsNotOverriden.ElementaryMethodsNotOverridenAnalyzer”引发异常,并显示消息“无法加载文件或程序集“RoslynTester,版本=1.0.0.0,Culture=neutral,PublicKeyToken=null”或其依赖项之一.系统找不到指定的文件。'。
使用fuslogvw.exe 给我this log information 归结为
LOG:所有探测 URL 都已尝试并失败。
在/Common7/IDE/ 的几个子文件夹中搜索.dll 和.exe 版本后。
作为澄清我为什么这样做的上下文:我想检查集合中使用的每个类型并验证它是否覆盖了Equals 和GetHashCode。为了确定这一点,我有一个“经典”反射扩展方法可以帮我检查:
public static bool IsOverridden(this MethodInfo method)
{
return method.GetBaseDefinition().DeclaringType != method.DeclaringType;
}
如果 Roslyn 有办法自己验证这一点,这样我就不必使用经典反射,那么这也可以。
更新:
当我使用此代码 as provided by MSDN 时,我在 Visual Studio 中收到“无效参数”异常,但 fuslogvw 仍然显示“找不到文件”错误消息。造成这种差异的原因是什么?
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;
}
【问题讨论】:
-
这是一个“找不到文件”错误,这是最常见的错误。非常不清楚为什么您认为 CLR 应该能够找到该文件。如果它不在 GAC 中并且不在探测路径中,那么这就是它的结束,Fuslogvw 向您展示了它的外观。您的 AssemblyResolve 事件不会完成任何事情,它只能找到之前已加载的程序集,并且 CLR 已经知道如何自行完成。
-
我已经研究了这些概念,但还有一些问题。我认为 GAC 不是一个解决方案,因为它会迫使用户手动将他的程序集添加到其中。此外:
RoslynTester项目只是一个控制台应用程序,诊断信息(依赖于从该程序集获取类型)应该在构建项目之前可用。当我在编译时不知道在哪个目录中找到新程序集时,如何将ResolveAssemblies指向新程序集?我已经更新了ResolveAssemblies代码。
标签: c# .net reflection .net-assembly roslyn