我正在嘗試使用Roslyn來生成和編譯包含get/set屬性的簡單對象的運行時庫。使用Roslyn編譯語法樹
但是,由於某些原因,編譯程序集時失敗,錯誤添加了Linq名稱空間(錯誤CS0246:無法找到類型或名稱空間名稱'System.Linq'(您是否缺少using指令或程序集引用?)})。
我試過用各種方法操作生成的樹並編譯每一個,但仍然編譯失敗。
編譯成功的唯一方法是如果樹被解析爲字符串,然後解析回語法樹,然後編譯。
下面的代碼執行以下操作:
- 構建包含編譯單元,usings,命名空間,類和屬性的簡單語法樹。
- 嘗試編譯樹(失敗)
- 生成新的語法樹與C#6選項並編譯(失敗)
- 格式語法樹和編譯(失敗)
- 序列化樹串,然後用SyntaxFactory .ParseSyntaxTree和編譯生成的樹(成功)
的代碼:
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 and 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 To 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 to compile syntax tree root");
// Try to 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 to compile new syntax tree");
// Try to 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 to compile formatted syntax tree");
// Try to serialize and 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 to 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;
}
}
作品!非常感謝,在這個問題上我突然想到了。 –