CodeDomProvider代码生成因某些Linq语法而失败

本文关键字:语法 失败 Linq 代码生成 CodeDomProvider | 更新日期: 2023-09-27 18:27:08

我正在使用CodeDomProvider编译一些Linq代码并动态执行查询。然而,我遇到了一个非常奇怪的问题。

如果我在生成的代码中的Linq查询看起来像这样,那么一切都正常:

namespace Dynamic
{
    using System.Linq;
    using System.Collections.Generic;
    public static class Query
    {
        public static int GetRecords()
        {
            MyData.Data.DataMart container = new MyData.Data.DataMart();
            return (container.EventDetails).Count();
        }
    }
}

这编译和运行都很好。然而,如果我将linq查询更改为以下内容,那么它将无法编译:

return (from e in container.EventDetails select e).Count();

如果我把它作为静态代码,它会很好地工作,但如果我试图用CodeDomProvider编译它,它会失败(我还没有找到任何好的方法来获取关于它失败原因的错误消息)。我想使用from in select风格的语法,因为这会让我更容易生成linq查询,但我不明白为什么它们没有编译。

你可以在这篇文章顶部的链接中看到我用来编译这个片段的一些代码。

谢谢!

编辑:从我链接到的帖子复制代码:

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true;
cp.ReferencedAssemblies.Add("mscorlib.dll");
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.Data.Linq.dll");
cp.ReferencedAssemblies.Add("System.Data.Entity.dll");
cp.ReferencedAssemblies.Add("MyApp.Data.dll");
var results = provider.CompileAssemblyFromSource(cp, source);
var assm = results.CompiledAssembly; 

Edit2:就异常而言,我在代码的倒数第二行得到一个异常(var results=…)。该异常是BadImageFormatException:

无法加载从系统加载的文件或程序集"0字节",版本=4.0.0.0,区域性=中性,PublicKeyToken=b77a5c561934e089'或它的一个依赖项。试图用格式不正确

CodeDomProvider代码生成因某些Linq语法而失败

这似乎对我有用:

    static void Main(string[] args)
    {
        string sourceCode = @"namespace Dynamic {
using System.Linq;
using System.Collections.Generic;
public static class Query
{
    public static int GetRecords()
    {
        MyApp.Data.DataMart container = new MyApp.Data.DataMart();
        //return (container.EventDetails).Count();
        return (from e in container.EventDetails select e).Count();
    }
} }";
        string sDynamDll = "Dynamic.dll";
        string sDynamClass = "Query";
        string sDynamMethod = "GetRecords";
        System.CodeDom.Compiler.CompilerParameters cp = new CompilerParameters();
        cp.GenerateExecutable = false;
        cp.GenerateInMemory = true;
        cp.OutputAssembly = sDynamDll;
        cp.ReferencedAssemblies.Add("mscorlib.dll");
        cp.ReferencedAssemblies.Add("System.dll");
        cp.ReferencedAssemblies.Add("System.Core.dll");
        cp.ReferencedAssemblies.Add("System.Data.Linq.dll");
        cp.ReferencedAssemblies.Add("System.Data.Entity.dll");
        cp.ReferencedAssemblies.Add("MyApp.Data.dll");
        var providerOptions = new Dictionary<string, string>();
        providerOptions.Add("CompilerVersion", "v4.0");
        CodeDomProvider compiler = CodeDomProvider.CreateProvider("C#", providerOptions);
        CompilerResults cr = compiler.CompileAssemblyFromSource(cp, sourceCode);
        if (cr.Errors.HasErrors)
        {
            StringBuilder errors = new StringBuilder("Compiler Errors :'r'n");
            foreach (CompilerError error in cr.Errors)
            {
                errors.AppendFormat("Line {0},{1}'t: {2}'n", error.Line, error.Column, error.ErrorText);
            }
        }
        // verify assembly
        Assembly theDllAssembly = null;
        if (cp.GenerateInMemory)
            theDllAssembly = cr.CompiledAssembly;
        else
            theDllAssembly = Assembly.LoadFrom(sDynamDll);
        Type theClassType = theDllAssembly.GetType(sDynamClass);
        foreach (Type type in theDllAssembly.GetTypes())
        {
            if (type.IsClass == true)
            {
                if (type.FullName.EndsWith("." + sDynamClass))
                {
                    theClassType = type;
                    break;
                }
            }
        }
        // invoke the method
        if (theClassType != null)
        {
            object[] method_args = new object[] { };
            Object rslt = theClassType.InvokeMember(
                sDynamMethod,
              BindingFlags.Default | BindingFlags.InvokeMethod,
                   null,
                   null, // for static class
                   method_args);
            Console.WriteLine("Results are: " + rslt.ToString());
        }
        Console.ReadKey();
    }

您可能会得到BadImageFormatException,因为您的代码实际上并没有编译到有效的程序集。这可能是因为默认情况下使用旧的2.0编译器。检查下面的链接以启用C#3.5版本(我不知道是否支持4.0,但你不需要它):

http://blogs.msdn.com/b/lukeh/archive/2007/07/11/c-3-0-and-codedom.aspx

还要检查从CompileAssemblyFromSource()方法返回的CompilerResult上的Errors集合。编译失败不会引发异常,您必须手动检查编译错误。

我没有找到如何获得良好异常信息的答案,但我确实解决了这个问题。包含上面编译器代码的类库被设置为AnyCpu,但它在ASP.Net下运行的上下文是x86。因此,这导致它在尝试加载System.dll时失败,因为它加载了错误的版本(或类似的愚蠢版本)。

如果你能(a)弄清楚如何从中获得真正的错误消息,或者(b)加载正确的引用类型,我很乐意给其他人答案复选标记。