質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

0回答

1094閲覧

Roslyn CodeAnalysisでenumの値を取得したい

ttact

総合スコア170

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2020/09/07 02:42

編集2020/09/07 04:04

■課題
Roslyn(Microsoft.CodeAnalysis)を使ってC#ソースコードを解析し、enumとそれに含まれる列挙子を抽出するプログラムを書いています。

各列挙子の値について、簡単かつRoslynが算出した値を取得する手段を探しています。

■試したこと
以下のI/Fはダメでした:

  • SemanticModel.GetConstantValue()は、nullが返る。
  • SemanticModel.GetDeclaredSymbol();で戻ってくるIFieldSymbolのConstantValueには、nullが入っている。

■回避策
以下は対応アイディアとして検討していますが、さらに楽な手段がないか探しています。

(1)
「列挙子シンボル = 値,」の形式で記述しているケースでは、EnumDeclarationSyntax.EqualsValueによって「 = 値」の部分を取得できます。なので本文字列をパースして自前で算出すれば値は得られます。
これを避けているのは、Roslynは元々コンパイラで、アセンブリを生成する過程では同様にパース・値算出を行っているはずです。
車輪の再発明をしたくない(結果を食い違いさせたくない)ですし、I/Fが提供されているなら自作は避けたいです。

(2)
CSharpCompilation.Emit()によってメモリ上でビルドして、得たアセンブリをリフレクションで解析する。
これを避けているのは、単に手間がかかるからです。Roslynの算出結果を利用しているという点では要求を満たします。

■環境
VS2017(ver.15.9.26)
C#プロジェクト(.NET Framework 4.7.2)
nugetでMicrosoft.CodeAnalysis(ver.3.7.0)を取得

■実装中のコード

C#

1var srcCode = File.ReadAllText(path); 2var syntaxTree = CSharpSyntaxTree.ParseText(srcCode); 3var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, null); 4var semanticModel = compilation.GetSemanticModel(syntaxTree); 5var nodes = syntaxTree.GetRoot().DescendantNodes(); 6foreach(var syntax in nodes.OfType<EnumDeclarationSyntax>()) 7{ 8 foreach(var memberSyntaxTree in syntax.Members) 9 { 10 var symbol = semanticModel.GetDeclaredSymbol(memberSyntaxTree); 11 12 // ダメなコードの例。 13 var value = semanticModel.GetConstantValue(memberSyntaxTree); 14 15 Console.WriteLine($"{symbol} = {value}"); 16 } 17}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/09/07 03:11

> 「列挙子シンボル,」の形式で記述しているケースで値を取得する場合はどうしたらよいのでしょうか。 0 からの通し番号です。
ttact

2020/09/07 03:35

C#規格的に0からの通し番号であることは理解しております。 また質問からは書き洩らしていましたが、EnumDeclarationSyntax.EqualsValueをパースして各値を計算できる(EqualsValueがnullなら初期値0とする)ことも承知しております。 しかし、Roslynは内部機能として列挙子の各値をパースし算出しているはずです。ここを車輪の再発明したくはないですし、取得I/Fがあればそれを利用したいと思い、本質問を立てています。 Emit()の下りは、結局アセンブリを生成するまで算出しておらず、結果としてI/Fが提供されないということを想定して記述しています。
Zuishin

2020/09/07 03:53

そのような後出しがいくつも出るので回答がつきにくいんだと思います。質問を編集することをお勧めします。 > 他にもっと楽な方法がないかと思い 特にこの部分を書き換え、主題をはっきりさせた方が回答しやすいのではないかと思います。「楽な書き方」を求めているように見えます。
ttact

2020/09/07 04:30 編集

質問の本質的には、まさに「楽な書き方」を求めています。Emit()でコンパイルし、アセンブリをパースすることは、記述が長くなりますし処理時間も余計にかかりますから。既存のI/Fがあればそれを利用すべきだと思います。 質問内容については、前提条件を付記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問