考虑下面的类在一个文件“MyClass.cs”
using System; public class MyClass : Entity<long> { public long Id { get; set; } [required] public string Name { get; set; } public string Slug { get; set; } public DateTime CreatedOn { get; private set; } public DateTime UpdatedOn { get; private set; } /* ... */ }
目前我手动创建数据契约类,如下所示:
[DataContract(Namespace = "http://example.com/",Name = "MyClass")] public sealed class MyClass { [DataMember(EmitDefaultValue = false,Name = "Id")] public long Id { get; set; } [DataMember(EmitDefaultValue = false,Name = "Name",Isrequired = true)] public string Name { get; set; } [DataMember(EmitDefaultValue = false,Name = "Slug")] public string Slug { get; set; } [DataMember(EmitDefaultValue = false,Name = "CreatedOn")] public DateTime CreatedOn { get; set; } [DataMember(EmitDefaultValue = false,Name = "UpdatedOn")] public DateTime UpdatedOn { get; set; } }
我想使用Roslyn重写“MyClass.cs”,所以它看起来像我手工创建的类.目前我有以下:
using System; using System.IO; using Roslyn.Compilers.CSharp; internal class Program { private static void Main() { var reader = new StreamReader(@"..\..\MyClass.cs"); var source = reader.ReadToEnd(); var tree = SyntaxTree.ParseCompilationUnit(source); var rewriter = new MyRewriter(); var newRoot = rewriter.Visit(tree.Root); Console.WriteLine(newRoot.Format()); } } public class MyRewriter : SyntaxRewriter { protected override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) { var declaration = (TypeDeclarationSyntax) base.VisitClassDeclaration(node); return ((ClassDeclarationSyntax) declaration).Update( declaration.Attributes,Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword),Syntax.Token(SyntaxKind.SealedKeyword)),declaration.Keyword,declaration.Identifier,declaration.TypeParameterListOpt,null,declaration.ConstraintClauses,declaration.OpenBraceToken,declaration.Members,declaration.CloseBraceToken,declaration.SemicolonTokenOpt); } protected override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node) { var typeSyntax = node.Type; if (node.Identifier.ValueText == "Id") { typeSyntax = Syntax.IdentifierName("string"); } var newProperty = Syntax.PropertyDeclaration( modifiers: Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword)),type: typeSyntax,identifier: node.Identifier,accessorList: Syntax.AccessorList( accessors: Syntax.List( Syntax.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration,semicolonTokenOpt: Syntax.Token(SyntaxKind.SemicolonToken)),Syntax.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration,semicolonTokenOpt: Syntax.Token(SyntaxKind.SemicolonToken)) ) ) ); return newProperty; } }
我一直在尝试找到一种方法来将DataMember和DataContract自定义属性添加到MyClass,但是不成功.如何添加自定义属性?
解决方法
Syntax.PropertyDeclaration方法的一个参数是应用于该属性的属性列表.与所有Syntax元素一样,它使用静态SyntaxFactory类中的工厂方法构造.
Roslyn Quoter可以方便地找出如何使用Roslyn生成语法.
在您的具体示例中,重写器的VisitPropertyDeclaration方法应如下所示:
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; ... protected override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node) { var typeSyntax = node.Type; if (node.Identifier.ValueText == "Id") { typeSyntax = SyntaxFactory.IdentifierName("string"); } var newProperty = PropertyDeclaration( PredefinedType( Token(SyntaxKind.LongKeyword)),Identifier("Id")) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))) .WithAccessorList( AccessorList( List(new AccessorDeclarationSyntax[]{ AccessorDeclaration( SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken( Token(SyntaxKind.SemicolonToken)),AccessorDeclaration( SyntaxKind.SetAccessorDeclaration) .WithSemicolonToken( Token(SyntaxKind.SemicolonToken))}))) .NormalizeWhitespace(); return newProperty; }