LoginSignup
8
0

Roslyn API でフィールドとプロパティの型と名称を取得する

Last updated at Posted at 2023-12-13

はじめに

この記事は株式会社ラグザイア Advent Calendar 2023の記事です。

前回は Roslyn API のざっくりした概要の紹介とフィールドの名称を取得してみました。
今回はRoslyn API でフィールドとプロパティの型と名称を取得してみます。

先に忙しい方向けに、Roslyn API でフィールドとプロパティの型と名称を取得するコードを貼っておきます。

program.cs
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace SyntaxQuickStart
{
    class Program
    {
        const string programText =
@"namespace DummyNamespace
{
    internal class Dummy
    {
        public string DummyField = ""フィールドです"";
        public int DummyProperty => 123;
    }
}";

        static void Main()
        {
            SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
            CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

            // フィールドを取得
            FieldDeclarationSyntax field = root.DescendantNodes().OfType<FieldDeclarationSyntax>().First();

            Console.WriteLine("------------------ フィールドの情報 ------------------");
            // フィールドの名称を表示
            Console.WriteLine(field.Declaration.Variables.First().Identifier.ValueText);
            // フィールドの型を表示
            Console.WriteLine(field.Declaration.Type.ToString());

            // プロパティを取得
            PropertyDeclarationSyntax property = root.DescendantNodes().OfType<PropertyDeclarationSyntax>().First();

            Console.WriteLine("------------------ プロパティの情報 ------------------");
            // プロパティの名称を表示
            Console.WriteLine(property.Identifier.ValueText);
            // プロパティの型を表示
            Console.WriteLine(property.Type.ToString());
        }
    }
}

フィールドの型を取得する

前回は Roslyn API を使ってフィールドの名称を表示するところまで行いました。同様に Roslyn API を使ってフィールドの型を表示してみましょう。

フィールドの名称の場合、コード解析後のツリーから FieldDeclarationSyntaxOfType を使って絞り込み、 field.Declaration.Variables.First().Identifier.ValueText のような形で名称を取りだしていました。コードはこんな感じでした。

var tree = CSharpSyntaxTree.ParseText(programText);
var root = tree.GetCompilationUnitRoot();

// フィールドを取得
var field = root.DescendantNodes().OfType<FieldDeclarationSyntax>().First();

// フィールドの名称を標準出力に表示
Console.WriteLine(field.Declaration.Variables.First().Identifier.ValueText);

Declaration プロパティがフィールドに関するあれこれの情報をもっていそうです。 Declaration の正体である VariableDeclarationSyntax を見ると Type プロパティを発見しました。これが使えそうです。

// フィールドを取得
FieldDeclarationSyntax field = root.DescendantNodes().OfType<FieldDeclarationSyntax>().First();
// フィールドの型を表示
Console.WriteLine(field.Declaration.Type.ToString());

これを前回のコードに追加して表示してみます。

program.cs
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace SyntaxQuickStart
{
    class Program
    {
        const string programText =
@"namespace DummyNamespace
{
    internal class Dummy
    {
        public string DummyField = ""フィールドです"";
    }
}";

        static void Main()
        {
            SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
            CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

            // フィールドを取得
            FieldDeclarationSyntax field = root.DescendantNodes().OfType<FieldDeclarationSyntax>().First();

            Console.WriteLine("------------------ フィールドの情報 ------------------");
            // フィールドの名称を表示
            Console.WriteLine(field.Declaration.Variables.First().Identifier.ValueText);
            // フィールドの型を表示
            Console.WriteLine(field.Declaration.Type.ToString());
        }
    }
}

実行結果です。無事にフィールドの型である string が表示できました。
Monosnap ~_works_SyntaxQuickStart 2023-11-27 16.35.png

プロパティの情報を取得する

フィールドの名称と型の情報は取得できました。同様にプロパティの情報も取得していきましょう。

プロパティの名称を取得する

フィールドの場合↓のような形で名称 = 識別子を取得できていました。

var tree = CSharpSyntaxTree.ParseText(programText);
var root = tree.GetCompilationUnitRoot();

// フィールドを取得
var field = root.DescendantNodes().OfType<FieldDeclarationSyntax>().First();

// フィールドの名称を標準出力に表示
Console.WriteLine(field.Declaration.Variables.First().Identifier.ValueText);

↑でいけるのであれば FieldDeclarationSyntax の部分を PropertyDeclarationSyntax に変えるだけでいけるのでは?と予想してみました。やってみましょう。こうです!えいや!

// フィールドを取得して名称を表示(ネタバレ:エラーになります)
PropertyDeclarationSyntax property = root.DescendantNodes().OfType<PropertyDeclarationSyntax>().First();
Console.WriteLine(property.Declaration.Variables.First().Identifier.ValueText);

すると残念なことにエラーになりました。PropertyDeclarationSyntaxDeclaration というプロパティは持たないようです。ちくしょう…

image.png

PropertyDeclarationSyntax の解説ページを見ると Identifier プロパティがありました。
property.Identifer で一気に識別子(名称)の値が取れるみたいです。つまり、こうです。

PropertyDeclarationSyntax property = root.DescendantNodes().OfType<PropertyDeclarationSyntax>().First();
Console.WriteLine(property.Identifier.ValueText);

前回のコードに加えて出力させてみましょう。

program.cs
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace SyntaxQuickStart
{
    class Program
    {
        const string programText =
@"namespace DummyNamespace
{
    internal class Dummy
    {
        public string DummyField = ""フィールドです"";
        public int DummyProperty => 123;
    }
}";

        static void Main()
        {
            SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
            CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

            // フィールドを取得
            FieldDeclarationSyntax field = root.DescendantNodes().OfType<FieldDeclarationSyntax>().First();

            Console.WriteLine("------------------ フィールドの情報 ------------------");
            // フィールドの名称を表示
            Console.WriteLine(field.Declaration.Variables.First().Identifier.ValueText);
            // フィールドの型を表示
            Console.WriteLine(field.Declaration.Type.ToString());

            // プロパティを取得
            PropertyDeclarationSyntax property = root.DescendantNodes().OfType<PropertyDeclarationSyntax>().First();

            Console.WriteLine("------------------ プロパティの情報 ------------------");
            // プロパティの名称を表示
            Console.WriteLine(property.Identifier.ValueText);
        }
    }
}

実行結果です。プロパティの名称である DummyProperty が表示されました。いえーい。
Monosnap ~_works_SyntaxQuickStart 2023-11-27 16.47.png

プロパティの型を取得する

プロパティの名称と同じようにPropertyDeclarationSyntax から何かできないかと見てみると、 Type プロパティがありました。これは勝ち確定パターンです。

こう書けそうです。

// プロパティを取得
PropertyDeclarationSyntax property = root.DescendantNodes().OfType<PropertyDeclarationSyntax>().First();
// プロパティの型を表示
Console.WriteLine(property.Type.ToString());

今までのコードに追加してみます。

program.cs
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace SyntaxQuickStart
{
    class Program
    {
        const string programText =
@"namespace DummyNamespace
{
    internal class Dummy
    {
        public string DummyField = ""フィールドです"";
        public int DummyProperty => 123;
    }
}";

        static void Main()
        {
            SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
            CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

            // フィールドを取得
            FieldDeclarationSyntax field = root.DescendantNodes().OfType<FieldDeclarationSyntax>().First();

            Console.WriteLine("------------------ フィールドの情報 ------------------");
            // フィールドの名称を表示
            Console.WriteLine(field.Declaration.Variables.First().Identifier.ValueText);
            // フィールドの型を表示
            Console.WriteLine(field.Declaration.Type.ToString());

            // プロパティを取得
            PropertyDeclarationSyntax property = root.DescendantNodes().OfType<PropertyDeclarationSyntax>().First();

            Console.WriteLine("------------------ プロパティの情報 ------------------");
            // プロパティの名称を表示
            Console.WriteLine(property.Identifier.ValueText);
            // プロパティの型を表示
            Console.WriteLine(property.Type.ToString());
        }
    }
}

実行結果です。プロパティの型の int が出力できました!
Monosnap ~_works_SyntaxQuickStart 2023-11-27 16.52.png

次回予告

ということで Roslyn API を使ってフィールドとプロパティの型と名称を取得することができました。次回は Roslyn API を使おうと思ったきっかけの「コメント」の取得に挑みます。乞うご期待。

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0