如何强制加载项目未明确使用的引用程序集

时间:2017-11-22 12:39:23

标签: c# .net

我有以下情况:

一个主机应用程序,托管(win)表单,这些表单在同一解决方案的其他项目中定义。托管表单都实现了相同的界面。由于主机应用程序引用了所有其他项目,因此不涉及(并且不需要)动态加载(汇编解析)。

现在我认为我可以迭代AppDomain.CurrentDomain.GetAssemblies(),获取所有类型并过滤哪些类型实现我的界面。但由于我从未明确使用主机项目中的其他项目,因此程序集将不会加载到主机应用程序中,因此AppDomain.CurrentDomain.GetAssemblies()将不会列出它们。

我认为在大多数情况下这种行为是好的,但在我的情况下(反射使用),这是一个问题。有没有办法强制加载(特定)引用但未明确使用的程序集?我正在寻找视觉工作室/项目设置方式来做到这一点 - 我不喜欢编写代码来获取已经引用的程序集的想法:(

可能的解决方案:

  • 为每个程序集调用Assembly.Load。 con:主机应用中的代码更改
  • 从表单项目中调用已知的类/方法以强制加载。 con:主机应用程序中的代码更改以及要调用的类/方法的知识

1 个答案:

答案 0 :(得分:2)

根据 TnTinMn 的评论回答。谢谢你的建议!

  • 将静态Program类(主机应用的入口点)更改为partial
  • 创建名为Program.AssemblyLoader.tt
  • 的TextTemplate / T4文件
  • 添加以下内容:

Program.AssemblyLoader.tt

<#@ template language="C#" hostSpecific="true" debug="True" #>
<#@ output extension="cs" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="EnvDte" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System" #>
<#

    var visualStudio = (EnvDTE.DTE)(Host as IServiceProvider).GetService(typeof(EnvDTE.DTE));
    var solution = (EnvDTE.Solution)visualStudio.Solution;
    var projects = solution.Projects;

    // Assume that the first item is the main project, the host app.
    // Index is **NOT** zero-based!
    var main = (EnvDTE.Project)projects.Item(1);
    var p = main.Properties.Item("DefaultNamespace");
    var ns = p.Value.ToString();

#>
using System;
using System.Linq;
using System.IO;
using System.Reflection;

namespace <# WriteLine(ns); #>
{
    static partial class Program
    {
        static Program()
        {
            //! Generated file. Do not edit. Check the .tt file instead!
<#
foreach(EnvDTE.Project proj in projects)
{
    if(proj.Properties == null || proj.Properties.Item("OutputFileName") == null)
        continue;

    EnvDTE.Property p2 = proj.Properties.Item("OutputFileName") as EnvDTE.Property;
    WriteLine("            LoadAssemblyIfNecessary(\"" + p2.Value + "\");");
}
#>
        }

        private static readonly AssemblyName[] REFS = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
        private static readonly string APP = Path.GetFileName(System.Windows.Forms.Application.ExecutablePath);

        private static void LoadAssemblyIfNecessary(string name)
        {
            if (string.Equals(name, APP, StringComparison.InvariantCultureIgnoreCase)) return;

            if (!REFS.Any(x => x.Name.StartsWith(Path.GetFileNameWithoutExtension(name), StringComparison.InvariantCultureIgnoreCase)))
            {
                AppDomain.CurrentDomain.Load(Path.GetFileNameWithoutExtension(name));
            }
        }
    }
}

生成的Program.AssemblyLoader.cs

的示例
using System;
using System.Linq;
using System.IO;
using System.Reflection;

namespace Your.Name.Space
{
    static partial class Program
    {
        static Program()
        {
            //! Generated file. Do not edit. Check the .tt file instead!
            LoadAssemblyIfNecessary("HostApp.dll");
            LoadAssemblyIfNecessary("Dependency1.dll");
            LoadAssemblyIfNecessary("Dependency2.dll");
            LoadAssemblyIfNecessary("Modul1.exe");
        }

        private static readonly AssemblyName[] REFS = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
        private static readonly string APP = Path.GetFileName(System.Windows.Forms.Application.ExecutablePath);

        private static void LoadAssemblyIfNecessary(string name)
        {
            if (string.Equals(name, APP, StringComparison.InvariantCultureIgnoreCase)) return;

            if (!REFS.Any(x => x.Name.StartsWith(Path.GetFileNameWithoutExtension(name), StringComparison.InvariantCultureIgnoreCase)))
            {
                AppDomain.CurrentDomain.Load(Path.GetFileNameWithoutExtension(name));
            }
        }
    }
}