我知道如何在方法中创建局部变量,例如:
LocalDeclarationStatement(VariableDeclaration(IdentifierName("MyClass"))
.WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("nameOfvariable"))
.WithInitializer(
EqualsValueClause(
ObjectCreationExpression(IdentifierName("MyClass")).WithArgumentList(arguments)
.WithNewKeyword(Token(SyntaxKind.NewKeyword)))))));
会给我:
MyClass nameOfvariable = new MyClass();
但是说我已经创建了一个字段,现在我只想初始化它(在方法,构造函数或任何东西中),如下所示:
nameOfVariable = new MyClass();
我该怎么做?我的猜测它与VariableDeclerator有关,但是我找不到一种正确的方法,所以我可以将它添加到包含StatementSyntaxes的列表中。我也可以将VariableDecleration更改为“VariableDeclaration(IdentifierName(”“))”,但这给了我一个丑陋的额外空间。
似乎我在与Roslyn的一些非常基本的东西挣扎,我试图检查http://roslynquoter.azurewebsites.net/,但这感觉就像是强制执行它的方式(感觉它创建的代码多于必要的代码)。
更新:应该澄清我知道如何创建方法/构造函数。当我只能访问字段名称和字段类型时,我只想找到一种初始化字段的方法。所以我想要生成的唯一代码是:
myField = new MyField();
答案 0 :(得分:4)
嗯,你几乎就在那里,你只需要创造所有这些。这应该做你感兴趣的事情:
const string source = @"
using System;
class MyClass
{
void Method()
{
MyClass nameOfVariable;
}
}
";
var tree = CSharpSyntaxTree.ParseText(source);
var compilation = CSharpCompilation.Create("MyCompilation", new[] { tree }, new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
var semanticModel = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();
var local = root.DescendantNodes().OfType<LocalDeclarationStatementSyntax>().First();
var declaration = local.Declaration;
var declarator = declaration.Variables.First();
var identifier = SyntaxFactory.IdentifierName("MyClass");
var objectCreationExpression = SyntaxFactory.ObjectCreationExpression(identifier, SyntaxFactory.ArgumentList(), null);
var equalsValueClause = SyntaxFactory.EqualsValueClause(objectCreationExpression);
var newDeclarator = declarator.WithInitializer(equalsValueClause).WithAdditionalAnnotations(Formatter.Annotation);
var newRoot = root.ReplaceNode(declarator, newDeclarator);
var formattedRoot = Formatter.Format(newRoot, Formatter.Annotation, new AdhocWorkspace());
Console.WriteLine(formattedRoot.GetText());
Console.Read();
一些解释:您创建了一个新标识MyClass
,将在ObjectCreationExpression
中使用。然后将所有内容包装在EqualsValueClause
中,并将其设置为声明符的初始值设定项。我们还将Formatter
注释添加到此节点,以便我们以后可以对其进行格式化,并且不会出现空白问题。
然后剩下的就是替换原始树中的节点,格式化它并且你已经完成了:
如果您想要将赋值与声明分开放置,那么您必须创建一个新的AssignmentExpression
并将其包装在ExpressionStatement
内。通常,表达式和语句是不同的概念,但是这个ExpressionStatement
允许我们将表达式视为一个重要的语句,因为方法的主体只接受语句。
在代码中,它看起来像这样:
internal static void Execute()
{
const string source = @"
using System;
class MyClass
{
void Method()
{
MyClass nameOfVariable, another;
}
}
";
var tree = CSharpSyntaxTree.ParseText(source);
var compilation = CSharpCompilation.Create("MyCompilation", new[] { tree }, new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
var semanticModel = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();
var local = root.DescendantNodes().OfType<LocalDeclarationStatementSyntax>().First();
var method = local.Ancestors().OfType<MethodDeclarationSyntax>().First();
var variableIdentifier = SyntaxFactory.IdentifierName("nameOfVariable");
var classIdentifier = SyntaxFactory.IdentifierName("MyClass");
var objectCreationExpression = SyntaxFactory.ObjectCreationExpression(classIdentifier, SyntaxFactory.ArgumentList(), null);
var assignment = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, variableIdentifier, objectCreationExpression);
var expressionStatement = SyntaxFactory.ExpressionStatement(assignment).WithAdditionalAnnotations(Formatter.Annotation);
var newMethod = method.AddBodyStatements(expressionStatement);
var newRoot = root.ReplaceNode(method.Body, newMethod.Body);
var formattedRoot = Formatter.Format(newRoot, Formatter.Annotation, new AdhocWorkspace());
Console.WriteLine(formattedRoot.GetText());
Console.Read();
}
结果:
答案 1 :(得分:1)
经过一些尝试和寻找后,我找到了答案。你可以使用一种叫做“AssignmentExpression”的东西。
以下是如何使用它的示例:
ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName("myField"),
ObjectCreationExpression(IdentifierName("MyClass")).WithArgumentList(arguments)
.WithNewKeyword(Token(SyntaxKind.NewKeyword))));
这会给你:
myField = new Myclass();
所以现在很容易将创建和赋值/初始化分成两个不同的语句。
请注意,我正在使用“使用静态Microsoft.CodeAnalysis.CSharp.SyntaxFactory;”所以我不必一直写SyntaxFactory。
答案 2 :(得分:0)
或者您可以转到“ http://roslynquoter.azurewebsites.net/”并将代码粘贴到小的文本框中,然后单击“获取Roslyn API调用以生成此代码”。
(我可以生成您上面发布的代码,但这有点长。所以我使用一个简单的示例。
例如,假设您粘贴“ DateTime mydate2 = new DateTime()”,该工具将生成以下代码:-
LocalDeclarationStatement(
VariableDeclaration(
IdentifierName("DateTime"))
.WithVariables(
SingletonSeparatedList<VariableDeclaratorSyntax>(
VariableDeclarator(
Identifier("mydate2"))
.WithInitializer(
EqualsValueClause(
ObjectCreationExpression(
IdentifierName("DateTime"))
.WithArgumentList(
ArgumentList())))))).WithSemicolonToken(
MissingToken(SyntaxKind.SemicolonToken)).NormalizeWhitespace()
然后,您只需要使用SyntaxFactory来修复代码,例如:-
var myDeclaratyion = SyntaxFactory.LocalDeclarationStatement(
SyntaxFactory.VariableDeclaration(
SyntaxFactory.IdentifierName("DateTime")).
WithVariables(
SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(
SyntaxFactory.VariableDeclarator(
SyntaxFactory.Identifier("mydate2")).
WithInitializer(
SyntaxFactory.EqualsValueClause(
SyntaxFactory.ObjectCreationExpression(
SyntaxFactory.IdentifierName("DateTime"))
.WithArgumentList(
SyntaxFactory.ArgumentList())))))).WithSemicolonToken(SyntaxFactory.MissingToken(SyntaxKind.SemicolonToken)).NormalizeWhitespace();