【问题标题】:How to return a custom class from CodeDom in C#?如何从 C# 中的 CodeDom 返回自定义类?
【发布时间】:2016-01-12 08:53:45
【问题描述】:

我想从 Codedom 创建的函数返回一个自定义类(例如User)。我的Userclass 与我的Windows Application 在同一解决方案中的另一个类库中,我用它来生成动态代码。

CompilerResult 返回以下错误:

The type or namespace name 'TestApp' could not be found (are you missing a using directive or an assembly reference?)

The type or namespace name 'User' could not be found (are you missing a using directive or an assembly reference?)

这是我的代码:

StringBuilder sbCode = new StringBuilder();

sbCode.Append(@"using System.Windows.Forms;");
sbCode.Append(@"using Nikola.BusinessIntelligence.Objects;");
sbCode.Append(@"using System.Collections.Generic;");
sbCode.Append(@"using System.Text;");
sbCode.Append(@"using Microsoft.CSharp;");
sbCode.Append(@"using TestApp.Data;"); // User class is in this Class Lib

sbCode.Append(" public class Test {");
sbCode.Append(tbCode.Text);
sbCode.Append("}");

var cp = new CompilerParameters()
{
    GenerateInMemory = true,
    GenerateExecutable = false,
    ReferencedAssemblies =
    {
        "System.dll",
        "System.Core.dll",
        "System.Windows.dll",
        "System.Windows.Forms.dll",
    },
};

using (CSharpCodeProvider codeProvider = new CSharpCodeProvider())
{
    CompilerResults res = codeProvider.CompileAssemblyFromSource(cp, sbCode.ToString());
    var type = res.CompiledAssembly.GetType("Test");
    var obj = Activator.CreateInstance(type);
    var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
}

这是我在 tbCode 文本框中编写的示例代码:

public User  Execute()
        {
            User usr = new User();
            return usr;
        }

【问题讨论】:

    标签: c# dll .net-assembly codedom


    【解决方案1】:

    显然,如果您在代码中键入using something;,则必须在CompilerParameters 中使用的引用程序集列表中添加something 相关的引用程序集:

    var cp = new CompilerParameters()
            {
                GenerateInMemory = true,
                GenerateExecutable = false,
                ReferencedAssemblies =
                {
                    "System.dll",
                    "System.Core.dll",
                    "System.Windows.dll",
                    "System.Windows.Forms.dll",
                    // I assume the following name of the assembly
                    // however you should update it to the relevant name if needed
                    "TestApp.Data.dll"
                    },
    
            };
    

    【讨论】:

    • 我的 CompilerResults 现在没有任何错误,但这次 res.CompiledAssembly.GetType("Test");返回空值。你有什么建议吗?
    • 您是否调试并检查形成的类字符串(sbCode)的格式是否正确?
    • @MohanPrasath,是的,我查过了。格式正确
    • @cagin 这是因为你添加了一个命名空间。这不是必需的。我已经检查了我机器上的代码,这应该可以工作。检查测试和用户的可见性(它应该是公开的)。删除命名空间或使用var type = res.CompiledAssembly.GetType("SomeNameSpace.Test");
    • 我很惊讶namespace 确实是可选的,但这有consequences (把所有东西都放在global 感觉不对)。
    【解决方案2】:

    两个问题:

    1. 你忘了namespace:

      sbCode.Append(" namespace SomeNameSpace{public class Test {");
      sbCode.Append(tbCode.Text);
      sbCode.Append("}}");
      
    2. 您正在尝试的代码中缺少=

      User usr = new User();
      

    关于编译器错误,您必须添加缺少的程序集。尝试像这样添加当前程序集使用的所有内容:

    var options = new CompilerParameters();
    // add all loaded assemblies
    options.ReferencedAssemblies.AddRange(
        AppDomain.CurrentDomain.GetAssemblies().Where(item => !item.IsDynamic).Select(item => item.Location).ToArray());
    options.GenerateExecutable = false;
    options.GenerateInMemory = true;
    
    // compile like this
    var result = provider.CompileAssemblyFromSource(options, source);
    if (result.Errors.HasErrors)
    {
        // deal with errors
    }
    

    【讨论】:

    猜你喜欢
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 2020-09-08
    相关资源
    最近更新 更多