c# - Compiling a Syntax Tree using Roslyn -
i'm trying use roslyn generate , compile runtime library of simple objects containing get/set properties.
however, reason, compiling assembly fails error of adding linq namespace (error cs0246: type or namespace name 'system.linq' not found (are missing using directive or assembly reference?)}).
i've tried manipulating generated tree in number of ways , compiling each, still compilation fails.
the way in compilation succeeds if tree parsed string, parsed syntax tree , compiled.
the code below following:
- build simple syntax tree containing compilation unit, usings, namespace, class , property.
- try compile tree (fails)
- generate new syntax tree c#6 option , compile (fails)
- format syntax tree , compile (fails)
- serialize tree string, use syntaxfactory.parsesyntaxtree , compile generated tree (success)
the code:
private static readonly csharpcompilationoptions defaultcompilationoptions = new csharpcompilationoptions(outputkind.dynamicallylinkedlibrary) .withoverflowchecks(true) .withplatform(platform.x86) .withoptimizationlevel(optimizationlevel.release) .withusings(defaultnamespaces); private static readonly ienumerable<string> defaultnamespaces = new[] { "system", "system.io", "system.net", "system.linq", "system.text", "system.text.regularexpressions" }; private static readonly ienumerable<metadatareference> defaultreferences = new[] { metadatareference.createfromfile(typeof (object).assembly.location), metadatareference.createfromfile(typeof (system.linq.enumerable).assembly.location), metadatareference.createfromfile(typeof (system.genericuriparser).assembly.location), metadatareference.createfromfile(typeof (microsoft.csharp.runtimebinder.runtimebinderexception).assembly.location) }; static void main(string[] args) { makeassembly(); console.readline(); } private static void makeassembly() { //compilation unit , usings compilationunitsyntax cu = syntaxfactory.compilationunit() .addusings(syntaxfactory.usingdirective(syntaxfactory.identifiername("system")), syntaxfactory.usingdirective(syntaxfactory.identifiername(typeof(system.linq.enumerable).namespace))) ; // namespace namespacedeclarationsyntax ns = syntaxfactory.namespacedeclaration(syntaxfactory.identifiername("roslyn")); // class classdeclarationsyntax classnode = syntaxfactory.classdeclaration("myclass") .addmodifiers(syntaxfactory.token(syntaxkind.publickeyword)) ; // property classnode= classnode.addmembers( syntaxfactory.propertydeclaration(syntaxfactory.parsetypename("int32"), "myproperty") .addaccessorlistaccessors( syntaxfactory.accessordeclaration(syntaxkind.getaccessordeclaration).withsemicolontoken(syntaxfactory.token(syntaxkind.semicolontoken)), syntaxfactory.accessordeclaration(syntaxkind.setaccessordeclaration).withsemicolontoken(syntaxfactory.token(syntaxkind.semicolontoken))). addmodifiers(syntaxfactory.token(syntaxkind.publickeyword))); ns = ns.addmembers(classnode); cu = cu.addmembers(ns); // try compile syntax tree root var root = cu.syntaxtree.getroot(); var st = root.syntaxtree; var assembly = compileandload(st); if (assembly != null) { console.writeline("success compile syntax tree root"); return; } else console.writeline("failed compile syntax tree root"); // try compile new syntax tree var stnew = syntaxfactory.syntaxtree(cu, csharpparseoptions.default.withlanguageversion(languageversion.csharp6)); assembly = compileandload(stnew); if (assembly != null) { console.writeline("success compile new syntax tree"); return; } else console.writeline("failed compile new syntax tree"); // try format node adhocworkspace cw = new adhocworkspace(); optionset options = cw.options; options = options.withchangedoption(csharpformattingoptions.newlinesforbracesinmethods, false); options = options.withchangedoption(csharpformattingoptions.newlinesforbracesintypes, false); syntaxnode formattednode = formatter.format(cu, cw, options); var stformat = syntaxfactory.syntaxtree(cu, csharpparseoptions.default.withlanguageversion(languageversion.csharp6)); assembly = compileandload(stformat); if (assembly != null) { console.writeline("success compile formatted syntax tree"); return; } else console.writeline("failed compile formatted syntax tree"); // try serialize , parse stringbuilder sb = new stringbuilder(); using (stringwriter writer = new stringwriter(sb)) { formattednode.writeto(writer); } var treeasstring = sb.tostring(); var stparsed = syntaxfactory.parsesyntaxtree(treeasstring); assembly = compileandload(stparsed); if (assembly != null) { console.writeline("success compile parsed syntax tree"); return; } else console.writeline("failed compile formatted syntax tree"); } private static assembly compileandload(syntaxtree st) { var compilation = csharpcompilation.create("testroslyn.dll", new syntaxtree[] { st }, null, defaultcompilationoptions); compilation = compilation.withreferences(defaultreferences); using (var stream = new memorystream()) { emitresult result = compilation.emit(stream); if (result.success) { var assembly = assembly.load(stream.getbuffer()); return assembly; } return null; } }
i fell trap roslyn also. using directive not expressed string each part of qualified name syntax node. need create node this
var qualifiedname= syntaxfactory.qualifiedname(syntaxfactory.identifiername("system"), syntaxfactory.identifiername("linq")); var usingdirective = syntaxfactory.usingdirective(qualifedname);
i wrote helper method convert string correct syntax node.
private usingdirectivesyntax createusingdirective(string usingname) { namesyntax qualifiedname = null; foreach (var identifier in usingname.split('.')) { var name = syntaxfactory.identifiername(identifier); if (qualifiedname != null) { qualifiedname = syntaxfactory.qualifiedname(qualifiedname, name); } else { qualifiedname = name; } } return syntaxfactory.usingdirective(qualifiedname); }
Comments
Post a Comment