我正在玩一个小小的想法,不确定它是否可行或有多大用处。
我正在尝试使用Roslyn CTP生成一个非常基本的EF Code First数据库。
代码:
var scriptEngine = new ScriptEngine(new[] { "System", "System.Core", typeof(DbContext).Assembly.Location });
var session = Roslyn.Scripting.Session.Create();
var t = scriptEngine.CompileSubmission<DbContext>(@"
using System.Data.Entity;
public class Car {
public int Id {get; set;}
public string Name {get; set; }
}
public class Context : DbContext {
public DbSet<Car> Cars {get; set; }
}
new Context();
", session);
t.Execute();
执行时我得到以下异常
例外:
未提供“提交#0 + Car”类型。使用Ignore方法或NotMappedAttribute数据批注检查未明确排除类型。验证类型是否已定义为类,不是原始类,嵌套类还是通用类,并且不从EntityObject继承。
查看可能出现的问题列表,我猜测Roslyn正在将嵌套类作为代码生成的一部分。这有意义,否则“新的Context();”调用需要包装到某种类/方法中。我可以发出一个程序集,它可以确认上述内容,但可能没有任何关于如何正确编写它的线索。
我也走了Syntax.ClassDeclaration的路线,但最终得到了几百行代码,只是为了创建一个具有1个属性的类,并没有明显的方法来实例化该类。
问题
是否有一种简单的方法可以在Roslyn中创建一个可公开访问的类(例如,没有嵌套在另一个类中)?
答案 0 :(得分:5)
您可以使用Roslyn根据源代码创建包含您的类型的实际DLL库,然后使用脚本中的那个:
var classCode = @"
using System.Data.Entity;
public class Car {
public int Id { get; set; }
public string Name { get; set; }
}
public class Context : DbContext {
public DbSet<Car> Cars { get; set; }
}";
var syntaxTree = SyntaxTree.ParseCompilationUnit(classCode);
var compilation = Compilation.Create(
"car",
new CompilationOptions(assemblyKind: AssemblyKind.DynamicallyLinkedLibrary))
.AddReferences(
new AssemblyFileReference(typeof(object).Assembly.Location), // mscorlib
new AssemblyFileReference(typeof(Uri).Assembly.Location), // System
new AssemblyFileReference(typeof(IOrderedQueryable<>).Assembly.Location), // System.Data
new AssemblyFileReference(typeof(DbContext).Assembly.Location) // EntityFramework
)
.AddSyntaxTrees(syntaxTree);
var dllPath = "car.dll";
using (var stream = File.OpenWrite(dllPath))
{
compilation.Emit(stream);
}
var code = @"new Context();";
var scriptEngine = new ScriptEngine(new[] { new FileInfo(dllPath).FullName, "EntityFramework" });
var context = scriptEngine.Execute<DbContext>(code);