Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何强制加载项目未显式使用的引用程序集_C#_.net - Fatal编程技术网

C# 如何强制加载项目未显式使用的引用程序集

C# 如何强制加载项目未显式使用的引用程序集,c#,.net,C#,.net,我有以下情况: 一个宿主应用程序,承载(win)在同一解决方案的其他项目中定义的表单。托管的表单都实现相同的接口。由于宿主应用程序引用了所有其他项目,因此不涉及(也不需要)动态加载(程序集解析) 现在我想我可以迭代AppDomain.CurrentDomain.getAssemblys(),获取所有类型并筛选实现我的接口的类型。但由于我从未明确使用主机项目中的其他项目,因此程序集不会加载到主机应用程序中,因此AppDomain.CurrentDomain.GetAssemblies()不会列出它

我有以下情况:

一个宿主应用程序,承载(win)在同一解决方案的其他项目中定义的表单。托管的表单都实现相同的接口。由于宿主应用程序引用了所有其他项目,因此不涉及(也不需要)动态加载(程序集解析)

现在我想我可以迭代AppDomain.CurrentDomain.getAssemblys(),获取所有类型并筛选实现我的接口的类型。但由于我从未明确使用主机项目中的其他项目,因此程序集不会加载到主机应用程序中,因此
AppDomain.CurrentDomain.GetAssemblies()
不会列出它们

我认为在大多数情况下,这种行为是好的,但在我的情况下(反射用法),这是一个问题。是否有办法强制加载引用但未明确使用的(特定)程序集?我正在寻找visual studio/项目设置的方法来实现这一点-我不喜欢编写代码来加载已被引用的程序集:(

可能的解决办法:

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

根据TnTinMn的评论回答。感谢您的建议

  • 将静态
    程序
    类(主机应用程序的入口点)更改为
    部分
  • 创建一个名为
    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));
            }
        }
    }
}

因此,您希望在不编写任何代码的情况下执行此操作,对吗?@Evk我不希望每次添加新项目时都添加代码。如果代码能够处理新添加的项目引用(忽略未引用的其他DLL)如果不做修改,这就可以了。请注意,这个答案已经有7年了。现在可能有更好的选择。我不确定这是否是您所寻求的,但您可以使用T4模板枚举解决方案中的所有项目及其引用的程序集,并输出一个包含信息的代码文件。+1我很高兴看到有人能够发表评论并研究/实现它以满足他们的需求。这在给我一个C&P答案的时代是如此罕见和美妙的体验。但是在这个例子中,用户必须创建自己的入口点,程序类,部分。这是用户必须满足的要求。在程序集是第三方,用户是只是消费者,他必须明确这一点。这让我烦恼了这么久。我得出的结论是,您可以向客户的项目程序集输出中注入模块初始值设定项。在c#9中,添加一个由
[模块:模块初始化器(typeof(ForeignAssembly.MyModuleInitializer))]修饰的c文件应该更容易一步。
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));
            }
        }
    }
}