5

私が遊んでいるちょっとしたアイデアですが、それが実行可能かどうか、または多くの用途があるかどうかはわかりません。

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();

実行すると、次の例外が発生します

例外:

タイプ 'Submission#0+Car' はマッピングされませんでした。Ignore メソッドまたは NotMappedAttribute データ注釈を使用して、型が明示的に除外されていないことを確認してください。型がクラスとして定義されていること、プリミティブ、ネスト、またはジェネリックではないこと、および EntityObject から継承されていないことを確認してください。

考えられる問題のリストを調べたところ、Roslyn がコード生成の一部としてネストされたクラスを作成していると推測されます。これは、それ以外の場合は意味があります。呼び出しは、何らかのクラス/メソッドにラップする必要があります。上記を確認するアセンブリを出力できますが、正しく記述する方法についての手がかりはおそらくないでしょう。

私も Syntax.ClassDeclaration の道をたどりましたが、1 つのプロパティを持つクラスを作成するためだけに数百行のコードを作成することになり、そのクラスをインスタンス化する明確な方法はありませんでした。

質問

パブリックにアクセスできる (たとえば、別のクラスにネストされていない) Roslyn でクラスを作成する簡単な方法はありますか?

4

1 に答える 1

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);
于 2012-02-05T01:59:46.710 に答える