【问题标题】:Create Instance from assembly and its dependencies in C#在 C# 中从程序集及其依赖项创建实例
【发布时间】:2010-10-02 23:34:29
【问题描述】:

我有一个应用程序(我们称之为 MyApp),它可以动态地为一个类创建源代码,然后编译它。当它编译源代码时,我还引用了另一个文件夹中已经存在的另一个 DLL(即这个新创建的类的基类)。我执行以下操作来编译和输出 DLL:

//Create a C# code provider 
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");

//Set the complier parameters
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = false;
cp.TreatWarningsAsErrors = false;
cp.WarningLevel = 3;
cp.OutputAssembly = "SomeOutputPathForDLL";

// Include referenced assemblies
cp.ReferencedAssemblies.Add("mscorlib.dll");
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.Data.dll");
cp.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
cp.ReferencedAssemblies.Add("System.Xml.dll");
cp.ReferencedAssemblies.Add("System.Xml.Linq.dll");
cp.ReferencedAssemblies.Add("MyApp.exe");
cp.ReferencedAssemblies.Add("SomeFolder\SomeAdditionalReferencedDLL.dll");

// Set the compiler options
cp.CompilerOptions = "/target:library /optimize";
CompilerResults cr = provider.CompileAssemblyFromFile(cp, "PathToSourceCodeFile");

稍后在我的应用程序中(或下次应用程序运行时)我尝试创建该类的实例。我知道新创建的类(我们称之为 Blah)和基类的 DLL 在哪里。我使用以下代码尝试创建新类的实例:

Assembly assembly = Assembly.LoadFile("PathToNewClassDLL");
Blah newBlah = assembly.CreateInstance("MyApp.BlahNamespace.Blah") as Blah;

当我像上面那样调用 Assembly.CreateInstance 时,我收到一条错误消息,指出它无法创建实例。当我检查 assembly.GetReferencedAssemblies() 它有标准引用和我的应用程序的引用(MyApp.exe),但它没有我最初编译类时使用的依赖基类的引用(SomeAdditionalReferencedDLL.dll) .

我知道我必须以某种方式添加基类引用才能创建实例,但我不确定如何执行此操作。当我拥有程序集及其所有依赖项时,如何从程序集中创建类的实例?

谢谢

【问题讨论】:

  • 只是好奇,但您是否尝试先将依赖项加载到应用程序域中,然后再加载自定义生成的依赖项?

标签: c# .net assemblies dependencies


【解决方案1】:
//Constructor
static MyClass()
    {
        //Provoque l'événement quand .Net ne sait pas retrouver un Assembly référencé
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

    }
    /// <summary>
    /// Mémorise les assembly référencés par d'autres qui ne sont pas dans le répertoire principal d'EDV
    /// </summary>
    static Dictionary<string, string> _AssembliesPath;
    /// <summary>
    /// .Net ne sait pas retrouver un Assembly référencé
    /// Cherche et charge d'après les assembly référencés par d'autres qui ne sont pas dans le répertoire principal d'EDV        
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    /// <returns></returns>
    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (_AssembliesPath != null && _AssembliesPath.ContainsKey(args.Name))
        {
            Assembly lAssembly = Assembly.LoadFile(_AssembliesPath[args.Name]);
            AddAssemblyReferencedAssemblies(lAssembly, System.IO.Path.GetDirectoryName(lAssembly.Location));
            return lAssembly;
        }
        Error = string.Format("L'assembly {0} n'a pu être chargé", args.Name);
        return null;
    }
    /// <summary>
    /// Mémorise les assembly référencés par d'autres qui ne sont pas dans le répertoire principal d'EDV        
    /// </summary>
    /// <param name="pAssembly"></param>
    /// <param name="psRootPath"></param>
    static void AddAssemblyReferencedAssemblies(Assembly pAssembly, string psRootPath)
    {
        if (_AssembliesPath == null) _AssembliesPath = new Dictionary<string, string>();
        foreach (AssemblyName lRefedAss in pAssembly.GetReferencedAssemblies())
            if (!_AssembliesPath.ContainsKey(lRefedAss.FullName))
            {
                string lsRoot = psRootPath + "\\" + lRefedAss.Name + ".";
                string lsExt;
                if (System.IO.File.Exists(lsRoot + (lsExt = "dll")) || System.IO.File.Exists(lsRoot + (lsExt = "exe")))
                {
                    _AssembliesPath.Add(lRefedAss.FullName, lsRoot + lsExt);
                }
            }
    }

//函数调用 装配 lAssembly = Assembly.LoadFile(lsExternalAssemblyPath); AddAssemblyReferencedAssemblies(lAssembly, System.IO.Path.GetDirectoryName(lsExternalAssemblyPath));

【讨论】:

    【解决方案2】:

    首先我认为你有循环依赖..你的最后一段总结了它。 您需要重新考虑您的应用程序并确定您的职责设置是否正确。

    为什么是循环依赖:

    要生成新的 dll,它需要 MyApp.exe;

    没有新的 dll 就无法使用 MyApp.exe。

    也许发布您的目标是什么,我们可以帮助您正确构建应用程序。

    MyApp.exe 应承担适当的职责,使新生成的程序集正常工作,而不需要 MyApp.exe 使用新 dll 中的对象。

    例如,您应该只对新生成的程序集执行 .....

        public static void RenderTemplate(String templatepath, System.IO.Stream outstream, XElement xml, Dictionary<String, object> otherdata)
        {
            var templateFile = System.IO.File.ReadAllText(templatepath);
    
            var interpreter = new Interpreter();
            interpreter.ReferencedAssemblies.Add("System.Core.dll"); // linq extentions
            interpreter.ReferencedAssemblies.Add("System.Xml.dll");
            interpreter.ReferencedAssemblies.Add("System.Xml.Linq.dll");
    
            interpreter.UsingReferences.Add("System.Linq");
            interpreter.UsingReferences.Add("System.Xml");
            interpreter.UsingReferences.Add("System.Xml.Linq");
            interpreter.UsingReferences.Add("System.Collections.Generic");
            interpreter.Execute(templateFile, outstream, xml, otherdata);
        }
    

    【讨论】:

      【解决方案3】:

      如果您手动加载外部 DLL(程序集),它不会自动加载您引用的内容。

      因此您必须创建一个 AssemblyLoader。检查您的程序集的引用程序集并自行加载它们的代码。

      有关驻留在计算机上奇怪文件夹中的引用程序集的复杂性,而不是与已编译的 DLL 一起,请查看 AppDomain.CurrentDomain.AssemblyResolve 事件。 (您使用它来欺骗 .NET 以接受正在加载的程序集,即使它不在 GAC 中或与您编译的 DLL 中)

      使用代码手动加载引用的 DLL 后,CreateInstance 将起作用。

      【讨论】:

        【解决方案4】:

        听起来您在动态生成的程序集中引用的程序集不在标准探测路径之一中。

        相对于其他一切,它位于何处?

        你应该打开fusion log viewer 看看哪里出了问题。

        【讨论】:

          【解决方案5】:

          我认为 .Net 正在尝试在您的 bin 或 GAC 中找到“SomeAdditionalReferencedDLL.dll”。在创建新的 Blah 之前,您是否尝试过为“SomeAdditionalReferencedDLL.dll”执行 Assembly.Load?

          【讨论】:

            【解决方案6】:

            您确定它在编译时引用了您认为它正在引用的 DLL 实例吗?它可能正在解析到您认为的其他地方的路径,以便在实例化您的类时,它无法再找到该 DLL。我建议获取编译过程和类型创建的 Fusion 日志,以了解如何解析类型。

            【讨论】:

              猜你喜欢
              • 2010-09-06
              • 2014-05-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-08-03
              • 1970-01-01
              • 2014-12-05
              • 1970-01-01
              相关资源
              最近更新 更多