【问题标题】:C# Loading assemblies dynamicallyC#动态加载程序集
【发布时间】:2016-10-24 09:08:11
【问题描述】:

在运行时将文本编译为动态对象时遇到问题。

我写了一段简单的代码来编译文本:

public class CompileFactory
{
    public dynamic Compile(String classCode, String mainClass, Object[] requiredAssemblies)
    {
        CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> 
          { 
             { "CompilerVersion", "v4.0" } 
          });

        CompilerParameters parameters = new CompilerParameters
        {
            GenerateExecutable = true,       // Create a dll
            GenerateInMemory = true,          // Create it in memory
            WarningLevel = 3,                 // Default warning level
            CompilerOptions = "/optimize",    // Optimize code
            TreatWarningsAsErrors = false     // Better be false to avoid break in warnings
        };

        // Add all extra assemblies required
        foreach (var extraAsm in requiredAssemblies)
        {
            parameters.ReferencedAssemblies.Add(extraAsm as string);
        }
        CompilerResults results = provider.CompileAssemblyFromSource(parameters, classCode);
        if (results.Errors.Count != 0)
        {
            return "FAILED";
        }
        return results.CompiledAssembly.CreateInstance(mainClass); ;
    }
}

这就是我使用Compile 方法的方式。

List<string> assemblies = new List<string>{"System.Net.Mail.dll", "System.Net.dll"};
dynamic obj = compile.Compile(fileText, pluginName, assemblies.ToArray()); 

如您所见,我有时会添加对额外程序集的引用。出于某种原因,当我将using System.Net; 添加到文本文件时,它不会被引用并且我得到错误。我正在编译的文本实际上是一个保存为文本的 .cs 文件。我想通过提取using * 并单独添加它们来解决这个问题,但是在添加System.Net.Mail.dll 时,找不到元数据文件。

有没有人经历过类似的事情?我真的很想将using * 添加到文件中并准备好使用它。 任何意见将不胜感激。

【问题讨论】:

  • 你能说明你是怎么称呼Compile的吗?我想看看你传递的论点
  • @PhilippeParé dynamic obj = compile.Compile(fileText, pluginName, assemblies.ToArray()); Assemblies 只是一个 List&lt;string&gt;{"System.Net.Mail.dll", "System.Net.dll"};
  • 您应该将此添加到您的帖子中,因为它与您的问题非常相关,请参阅下面的回答

标签: c# .net dynamic namespaces using


【解决方案1】:

这里的问题是System.Net.dll 不存在。您可以通过右键单击它被引用的位置并选择“转到定义”来检查 .Net 类型在哪个程序集中。这将打开一个选项卡,其中包含“来自元数据”的类定义。在这个文件的顶部,你有一个#region 显示这个类型的来源。在TcpClient 的情况下,我们可以看到:

#region Assembly System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.dll
#endregion

使用“System.dll”而不是“System.Net.dll”将您的呼叫更改为Compile,它应该可以正常工作

编辑/澄清:无法从 using 语句中获取程序集名称。

【讨论】:

  • 您找不到仅基于 using 语句所需的程序集。我建议您将所需的所有程序集放在参考资料中
  • 不清楚您要做什么。如果您需要在运行时执行一串代码,我强烈建议您知道引用了哪些程序集。特别是如果您不是编写代码字符串的人(网站上的用户)
  • 如果您在 Visual Studio 中缺少参考,您会收到类似 The type or namespace name 'MyControl' does not exist in the namespace 'MyNamespace' (are you missing an assembly reference? 的消息。如果我在哪里,我会为用户添加选项以选择要引用的程序集。您将它们列出一次并将选项呈现给用户。更简单、更安全、更轻松。
  • @RobinVanCleef:您需要以某种方式指定引用。 using 语句根本没有包含足够的信息。程序集可以位于任何地方,不同的程序集可以包含相同的命名空间,同一程序集的多个版本可以存在...如果您熟悉 Linqpad,您会看到它的 .linq 文件包含纯文本代码,带有包含引用的程序集路径的小型 xml 标头。
  • 你不需要“使用”。这与我们之前遇到的问题相同,程序集是 system.dll。只需转到 Visual Studio 中的 ObjectBrowser 窗口并查找 "System.Net.Mail" ,如果在底部没有看到程序集完整路径,请转到 System.Net,然后转到 System.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多