我正在使用CodeDomProvider to compile some Linq code并动态执行查询。但是,我遇到了一个非常奇怪的问题。
如果生成的代码中的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字节, Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089'或 其中一个依赖项。尝试加载带有的程序 格式不正确
答案 0 :(得分:3)
这似乎对我有用:
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();
}
答案 1 :(得分:0)
您可能正在获取BadImageFormatException
,因为您的代码实际上并未编译为有效的程序集。这可能是因为默认使用旧的2.0编译器。检查下面的链接以启用C#3.5版本(我不知道是否支持4.0,但您不需要它):
http://blogs.msdn.com/b/lukeh/archive/2007/07/11/c-3-0-and-codedom.aspx
同时检查Errors
方法返回的CompilerResult
上的CompileAssemblyFromSource()
集合。编译失败不会引发异常,您必须手动检查编译错误。
答案 2 :(得分:0)
我没有找到如何获得良好异常信息的答案,但是,我确实解决了这个问题。包含上述编译器代码的类库设置为AnyCpu,但它在ASP.Net下运行的上下文是x86。所以这导致它在尝试加载System.dll时失败,因为它加载了错误的版本(或类似的东西)。
如果可以(a)弄清楚如何从中获取真实的错误消息或(b)加载正确的引用类型,我将很乐意给别人一个答案复选标记。