c# – 使用Roslyn编译语法树

c# – 使用Roslyn编译语法树,第1张

概述我正在尝试使用Roslyn生成和编译包含get / set属性的简单对象的运行时库. 但是,由于某种原因,编译程序集失败,添加Linq名称空间时出错(错误CS0246:找不到类型或名称空间名称’System.Linq'(您是否缺少using指令或程序集引用?)}) . 我曾尝试以多种方式 *** 作生成的树并编译每个,但仍然编译失败. 编译成功的唯一方法是将树解析为字符串,然后解析回语法树然后编译. 以下 我正在尝试使用Roslyn生成和编译包含get / set属性的简单对象的运行时库.

但是,由于某种原因,编译程序集失败,添加Linq名称空间时出错(错误CS0246:找不到类型或名称空间名称’System.linq'(您是否缺少using指令或程序集引用?)}) .

我曾尝试以多种方式 *** 作生成的树并编译每个,但仍然编译失败.

编译成功的唯一方法是将树解析为字符串,然后解析回语法树然后编译.

以下代码执行以下 *** 作:

>构建一个包含编译单元,使用,命名空间,类和属性的简单语法树.
>尝试编译树(失败)
>使用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;        }    }
解决方法 罗斯林也陷入了这个陷阱. using指令不仅表示为字符串,限定名称的每个部分都是语法节点.您需要像这样创建节点

var qualifIEdname= SyntaxFactory.QualifIEdname(SyntaxFactory.IDentifIErname("System"),SyntaxFactory.IDentifIErname("linq"));     var usingDirective = SyntaxFactory.UsingDirective(qualifedname);

我编写了一个帮助方法来将字符串转换为正确的语法节点.

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);}
总结

以上是内存溢出为你收集整理的c# – 使用Roslyn编译语法树全部内容,希望文章能够帮你解决c# – 使用Roslyn编译语法树所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1221004.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存