.NET反思问题

时间:2010-01-26 12:04:43

标签: .net reflection

以下代码(打包在“控制台应用程序”Visual Studio项目中):

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace TestReflection
{
    class Program
    {
        static void Main(string[] args)
        {
            bool found = false;
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (assembly.GetType("System.Diagnostics.Process") != null)
                {
                    found = true;
                    break;
                }
            }
            Console.WriteLine(found);
            Console.ReadKey();
        }
    }
}

在调试模式(F5)下运行时打印'True',但在没有调试器(Ctrl-F5)的情况下启动时输出'False'。其他类显示类似的行为(System.Text.RegularExpressions.Regex),其他类在两种情况下都可以找到(System.IO.File)。

我可能错过了一些明显的东西 - 为什么会这样?

(在Visual Studio 2005和2008中都会发生同样的事情)。

更新

找到的集合列表:

调试模式:

mscorlib
TestReflection
System
Microsoft.VisualStudio.HostingProcess.Utilities
System.Windows.Forms

运行模式:

mscorlib
TestReflection

正如答案所暗示的那样,在运行模式下,系统组件丢失(未加载)。我的问题是我假设GetAssemblies()也返回未加载的程序集。

虽然这解释了System.Diagnostics.Process的行为,但为什么我的代码在运行和调试模式下都找到System.IO.File

谢谢!

更新2

我已经将代码更改为循环加载的程序集和当前程序集,收集这些程序集引用的程序集列表。如果在迭代加载的程序集后我找不到我正在寻找的类型,我开始加载并检查引用的程序集。

似乎即使我在项目中引用System.dll(我正在查看Visual Studio中'System'引用的属性),我的可执行文件也仅引用mscorlib.dll (根据Reflector)。

如何为System.dll添加“真实”引用?放置虚线

new System.Diagnostics.ProcessStartInfo();

Main的开头做了诀窍(事情按预期工作,Reflector在检查可执行文件时显示mscorlib.dllSystem.dll的引用),但它是一个hack。< / p>

再次感谢!

5 个答案:

答案 0 :(得分:11)

AppDomain.GetAssemblies不会返回您引用的所有程序集,而是返回当前已加载到appdomain中的所有程序集。

显然,您的应用程序不直接使用Diagnostics.Process类,因此在调试器外部运行时不会加载。

那么为什么我们找到System.IO.File而不是System.Diagnostics.Process? 原因是这两个类虽然位于同一个顶级命名空间System中,但实际上存在于两个不同的程序集中。如果在Visual Studio对象浏览器中查找这两个类,则很容易看到这一点。 File类恰好位于 mscorlib dll中,而Process类位于系统 dll中。

由于没有mscorlib,没有.Net应用程序可以在没有加载程序集的情况下运行,因为你没有加载System.dll,因为你没有引用该dll中的任何类型。

答案 1 :(得分:4)

VS中的调试器尽力欺骗并欺骗您以为您在生产计算机上运行应用程序。然而,它正在做一大堆你不会想到的东西,例如急切地装载组件,在通常被收集之后长时间保持vars活着等等。

在发布版本中,CLR不会将程序集加载到appdomain中,直到需要类型或类型实例来执行代码。调试时无法保证此行为。

如果您的代码对这些更改很敏感,我建议您重新设计或检查System.Diagnostics.Debugger.IsAttached.

答案 2 :(得分:0)

我认为某些程序集不是由您的项目直接引用的,但是当调试被调试器本身映射到您的进程时。

确保您要查找的装配体位于项目的References

答案 3 :(得分:0)

通常在需要之前不会加载程序集。在调试模式下运行时,调试器会在启动时加载Microsoft.VisualStudio.HostingProcess.Utilities程序集。我的猜测是这个程序集调用了System程序集,因此系统在启动时以调试模式加载。

答案 4 :(得分:0)

您可能会发现使用和不使用调试器来尝试这一行很有意思:

Console.WriteLine(Process.GetCurrentProcess().ProcessName);

简而言之,as @Will notes,当您在VS中运行附加的调试器时,您根本不会运行'您的exe',而是VS调试器为您设置的整个框架。情况会有所不同。