C#反射-在运行时确定依赖项的位置

安德鲁

在我目前正在从事的项目中,我们进行了大量工作来对表单进行样式设置,并使它们与业务规则更加一致。这涉及到诸如表格填充,更改标签,更改列标题等之类的事情-基本上是负载。

我被要求调查制作工具以比较原始表格和新表格的可行性,以查看发生了什么变化。我已经走了使用反射的路线-获取原始DLL并依次加载表单并比较控件(我想不出更简单的方法,因为我们的许多表单还有其他项目在运行时“注入”,因此无法对设计器文件进行比较。

在我的项目中,我创建了两个名为“ OriginalAssemblies”和“ CurrentAssemblies”的目录,并且在每个目录中都有一个依赖关系目录,其中包含与窗体相关的所有程序集。这些文件主要在原始文件和当前文件之间有所不同。

我的第一个方法基于目录读取程序集,然后将其存储在列表中-有一个用于原始,一个用于当前:

private static void LoadInAssemblies(string sourceDir, List<Assembly> assemblyList)
{
    DirectoryInfo dir = new DirectoryInfo(sourceDir);

    foreach (FileInfo currentFile in dir.GetFiles().Where(f => f.Name.Contains("dll")))
    {
        assemblyList.Add(Assembly.LoadFile(currentFile.FullName));
    }
}

这似乎可以很好地工作,因为它可以加载包含表单的DLL。接下来,我有一个方法以不同的形式加载并处理它们。这会运行,但是每次都会从同一目录加载依赖项

foreach (Assembly current in originalAssemblies)
{
    var items = current.GetTypes().Where(t => t.IsSubclassOf(typeof(Form)) && !t.Name.Contains("Base")).ToList();
    foreach (var newForm in items)
    {
        Object originalForm = Activator.CreateInstance(newForm);

        // get the associated assembly from the new form
        Object currentForm = Activator.CreateInstance (currentAssemblies.SelectMany(a => a.GetTypes()).Where (t => t.Name == newForm.Name).First());

        ((Form)originalForm).ShowDialog();
        ((Form)currentForm).ShowDialog();
    }
}

经过一番研究,我在app.config中找到了有关探测的参考,因此请按以下步骤进行设置:

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="OriginalAssemblies/Dependencies"/>
    </assemblyBinding>
</runtime>

现在,我意识到我可以将目录分开,并具有当前目录和原始目录,但是在这种情况下,它将无济于事,因为依赖文件夹中的DLL是相同的-只是不同的程序集版本。

我的问题是,基于上述代码,在创建对象currentForm以使用正确的目录(在本例中为CurrentAssemblies)时,有什么方法可以告诉GetType()命令?

测量

我可以加载同一种dll的多个版本。这是我想出的:

您将需要在两个 事件上使用AssemblyResolve事件AppDomain来自动处理项目中引用的dll文件的重定向(此处“当前” dll在“ bin”中,“原始” dll在“ bin / original”中):

private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    // Path for to "Current" dlls.
    string newPath = Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location),
        "bin", new AssemblyName(args.Name).Name + ".dll");

    if (File.Exists(newPath))
        return Assembly.LoadFrom(newPath);
    return args.RequestingAssembly;
}

private static Assembly CurrentDomain_AssemblyResolve_Original(object sender, ResolveEventArgs args)
{
    // Path for the "Original" dlls.
    string newPath = Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location),
        "bin", "original", new AssemblyName(args.Name).Name + ".dll");

    if (File.Exists(newPath))
        return Assembly.LoadFrom(newPath);
    return args.RequestingAssembly;
}

重要事项请确保将代码尽快放在下面(在第一个调用的构造函数中),否则事件订阅将不会被调用!:

private static readonly AppDomain OriginalAppDomain;

// Here, "Program" is my first class constructor called on startup.
static Program()
{
    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_AssemblyResolve;

    // Second app domain for old DLLs.
    OriginalAppDomain = AppDomain.CreateDomain("Original DLLs", new Evidence());
    OriginalAppDomain.AssemblyResolve += CurrentDomain_AssemblyResolve_Original;
    OriginalAppDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_AssemblyResolve_Original;
}

现在,您可以像下面这样一次性测试两个dll:

// Runs on current AppDomain.
new SpecialForm().ShowDialog();

// Runs on OriginalAppDomain (created above).
OriginalAppDomain.DoCallBack(() => new SpecialForm().ShowDialog());

可能的改进

AssemblyResolve也可以通过检查版本而不是目录来更改方法。因此,您将对Assembly将要加载的内容有更多控制

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在运行时确定对象类型-C#

来自分类Dev

在运行时从C#编辑WPF ListView项

来自分类Dev

c#在运行时更改标签(控件)的位置

来自分类Dev

C ++在运行时确定多态对象的类型

来自分类Dev

使用依赖项注入在运行时确定实现

来自分类Dev

在运行时更改选项卡项标题(WPF、c#)

来自分类Dev

如何在Castle Windsor for C#中解决运行时依赖项

来自分类Dev

如何在Castle Windsor for C#中解决运行时依赖项

来自分类Dev

在运行时编译/运行.java文件与反射

来自分类Dev

在运行时编译/运行.java文件与反射

来自分类Dev

在运行时确定C#P /调用结构对齐

来自分类Dev

是否可以在运行时确定对象选择的情况下使用C ++对象组成?

来自分类Dev

如何使面板在运行时不绘制C#

来自分类Dev

C#在运行时后期绑定卸载Dll

来自分类Dev

c#在运行时动态创建通用列表

来自分类Dev

C#在运行时启用/禁用网络跟踪?

来自分类Dev

如何使面板在运行时不绘制C#

来自分类Dev

C#在运行时切换枚举

来自分类Dev

c#在运行时动态创建通用列表

来自分类Dev

C# 表单在运行时添加控件

来自分类Dev

使用反射在运行时创建类

来自分类Dev

使用反射在运行时创建类

来自分类Dev

在C程序的运行时确定`OSTYPE`

来自分类Dev

运行时的C ++ CLR依赖关系

来自分类Dev

没有RTTI,在C ++中如何在运行时确定集合中的对象是否实现了接口

来自分类Dev

C#-将泛型接口转换为传递在运行时确定的类型<T>的泛型类

来自分类Dev

ASP.NET-C#反射:在运行时,AddObject导致“模棱两可的匹配找到异常”

来自分类Dev

在运行时初始化依赖项

来自分类Dev

Maven在运行时添加依赖项

Related 相关文章

热门标签

归档