COMU+
こみゅぷらす
Sep 27, 2013
小島 富治雄
Roslyn による Visual Studio のアドイン
COMU+
こみゅぷらす
自己紹介
• 小島 富治雄
• @Fujiwo
• 福井コンピュータアーキテクト株式会社
• Microsoft MVP C# (2005-2014)
COMU+
こみゅぷらす
本日の資料
• http://blog.shos.info/archives/2013/07/addinbyroslyn.html
にて公開します
• スライドは
http://www.slideshare.net/F...
COMU+
こみゅぷらす
宣伝
• 来週土曜
「Hokuriku.NET Vol.12 in 福井」
http://atnd.org/events/40509
※ 個人の体験です。効果には個人差があります。
COMU+
こみゅぷらす
Roslyn について
COMU+
こみゅぷらす
Roslyn
• C# や Visual Basic のコンパイラー
の内部の API 等を公開
• "Compiler as a Service" と表現
http://www.zdnet.com/blog/micr...
COMU+
こみゅぷらす
Microsoft “Roslyn” CTP
• http://msdn.microsoft.com/en-
us/vstudio/roslyn.aspx
COMU+
こみゅぷらす
Roslyn
• 参考: Channel 9 のビデオと資料
– Future directions for C# and Visual Basic -
BUILD2011 (September 15, 2011)
–...
COMU+
こみゅぷらす
Roslyn の機能
• C# や Visual Basic のソースコード解析機能
• Visual Studio の拡張機能
• C#スクリプト機能
• 等
http://www.zdnet.com/blog/mi...
COMU+
こみゅぷらす
本日のデモ
• 今日は、「ソースコード解析機能」を用いて、
簡単な Visual Studio のアドインを
• C# のソースコードを解析して、識別子等を数え
て、それを WPF で作成したウィンドウに表示
COMU+
こみゅぷらす
「Visual Studio アドイン」プロジェクトの新規作成
COMU+
こみゅぷらす
NuGet から Roslyn をインストール
COMU+
こみゅぷらす
Roslyn 追加後のプロジェクトの参照設定
COMU+
こみゅぷらす
ViewModel の作成
• 今回 WPF で出すウィンドウ用のViewModel
• ソースコード内の識別子や using、クラス等の
数を保持
※ 実装の参考:
「INotifyPropertyChanged の...
COMU+
こみゅぷらす
ViewModel
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Runtime.Comp...
COMU+
こみゅぷらす
ViewModelpublic class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyC...
COMU+
こみゅぷらす
ViewModel
int propertyCount = 0;
public int PropertyCount
{
get { return propertyCount; }
set {
if (value != ...
COMU+
こみゅぷらす
ViewModel
int lambdaCount = 0;
public int LambdaCount
{
get { return lambdaCount; }
set {
if (value != lambda...
COMU+
こみゅぷらす
Roslyn を用いたコード解析部
• Roslyn.Compilers.CSharp.SyntaxWalker
クラスを継承
• SyntaxWalker クラス
– Visitor パターン
– Visit メソッ...
COMU+
こみゅぷらす
Roslyn を用いたコード解析部
using Roslyn.Compilers.CSharp;
using System.IO;
using System.Text;
namespace AddinByRoslyn
...
COMU+
こみゅぷらす
Roslyn を用いたコード解析部
// ソース コードの中を解析
void Analyze(string sourceCode)
{
// Roslyn.Compilers.CSharp.SyntaxTree クラス...
COMU+
こみゅぷらす
Roslyn を用いたコード解析部// 識別子のノードの場合
public override void VisitIdentifierName(IdentifierNameSyntax node)
{
base.Vis...
COMU+
こみゅぷらす
Roslyn を用いたコード解析部
// プロパティのノードの場合
public override void VisitPropertyDeclaration(PropertyDeclarationSyntax
nod...
COMU+
こみゅぷらす
Roslyn を用いたコード解析部
// シンプルなラムダ式のノードの場合
public override void VisitSimpleLambdaExpression(SimpleLambdaExpression...
COMU+
こみゅぷらす
View.xaml
• XAML の Grid 内
– ViewModel の Result を表示するための
TextBox
– ViewModel の Data を表示するための
DataGrid
• プロジェクト...
COMU+
こみゅぷらす
View.xaml
<Window x:Class="AddinByRoslyn.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati...
COMU+
こみゅぷらす
View.xaml.cs
• ViewModel のインスタンスを保持
– DataContext
• コンストラクターで C# のソース ファイル名を
受け取る
– SyntaxCounter クラスで解析
COMU+
こみゅぷらす
View.xaml.cs
using System.Windows;
namespace AddinByRoslyn
{
public partial class View : Window
{
ViewModel v...
COMU+
こみゅぷらす
• ViewModel のインスタンスを保持
– DataContext
• コンストラクターで C# のソース ファイル名を
受け取る
– SyntaxCounter クラスで解析
COMU+
こみゅぷらす
Visual Studio アドイン部
• Visual Studio アドイン部のコード
をカスタマイズ
–プロジェクトの新規作成時に自動生成
された Connect.cs 内
–Exec メソッドの中で View ...
COMU+
こみゅぷらす
Visual Studio アドイン部
// カスタマイズする Exec メソッド
public void Exec(string commandName, vsCommandExecOption executeOpt...
COMU+
こみゅぷらす
実行結果
COMU+
こみゅぷらす
実行結果
COMU+
こみゅぷらす
まとめ
• 今日は、Roslyn を使って何種類かの文法要素を
数えただけ
• 同様の方法で、より複雑な解析を行ったり、一
部を変更できる
• Roslyn の機能は C# や Visual Basic のソース
コー...
COMU+
こみゅぷらす
Upcoming SlideShare
Loading in...5
×

Roslyn による Visual Studio のアドイン

595

Published on

2013-07-27 新宿, 東京
こみゅぷらす Tech Aid 2013
http://comuplus.net/CLT2013/

Published in: Technology, News & Politics
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
595
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
3
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Transcript of "Roslyn による Visual Studio のアドイン"

  1. 1. COMU+ こみゅぷらす Sep 27, 2013 小島 富治雄 Roslyn による Visual Studio のアドイン
  2. 2. COMU+ こみゅぷらす 自己紹介 • 小島 富治雄 • @Fujiwo • 福井コンピュータアーキテクト株式会社 • Microsoft MVP C# (2005-2014)
  3. 3. COMU+ こみゅぷらす 本日の資料 • http://blog.shos.info/archives/2013/07/addinbyroslyn.html にて公開します • スライドは http://www.slideshare.net/Fujiwo/roslyn-visual-studio
  4. 4. COMU+ こみゅぷらす 宣伝 • 来週土曜 「Hokuriku.NET Vol.12 in 福井」 http://atnd.org/events/40509 ※ 個人の体験です。効果には個人差があります。
  5. 5. COMU+ こみゅぷらす Roslyn について
  6. 6. COMU+ こみゅぷらす Roslyn • C# や Visual Basic のコンパイラー の内部の API 等を公開 • "Compiler as a Service" と表現 http://www.zdnet.com/blog/microsoft/microsofts-roslyn-compiler-as-a-service-support-unlikely-to-be-in-visual-studio-2012/10896 より
  7. 7. COMU+ こみゅぷらす Microsoft “Roslyn” CTP • http://msdn.microsoft.com/en- us/vstudio/roslyn.aspx
  8. 8. COMU+ こみゅぷらす Roslyn • 参考: Channel 9 のビデオと資料 – Future directions for C# and Visual Basic - BUILD2011 (September 15, 2011) – Going Deeper with Project Roslyn: Exposing the C# and VB compiler’s code analysis - Lang.NEXT 2012 (April 3, 2012) – Roslyn Anders Hejlsberg Q&A: TypeScript, C#, Roslyn, and More - Build 2013 (June 27, 2013)
  9. 9. COMU+ こみゅぷらす Roslyn の機能 • C# や Visual Basic のソースコード解析機能 • Visual Studio の拡張機能 • C#スクリプト機能 • 等 http://www.zdnet.com/blog/microsoft/microsofts-roslyn-compiler-as-a-service-support-unlikely-to-be-in-visual-studio-2012/10896 より
  10. 10. COMU+ こみゅぷらす 本日のデモ • 今日は、「ソースコード解析機能」を用いて、 簡単な Visual Studio のアドインを • C# のソースコードを解析して、識別子等を数え て、それを WPF で作成したウィンドウに表示
  11. 11. COMU+ こみゅぷらす 「Visual Studio アドイン」プロジェクトの新規作成
  12. 12. COMU+ こみゅぷらす NuGet から Roslyn をインストール
  13. 13. COMU+ こみゅぷらす Roslyn 追加後のプロジェクトの参照設定
  14. 14. COMU+ こみゅぷらす ViewModel の作成 • 今回 WPF で出すウィンドウ用のViewModel • ソースコード内の識別子や using、クラス等の 数を保持 ※ 実装の参考: 「INotifyPropertyChanged の実装に便利なクラスとコードスニペット」
  15. 15. COMU+ こみゅぷらす ViewModel using System; using System.ComponentModel; using System.Linq.Expressions; using System.Runtime.CompilerServices; namespace AddinByRoslyn { public static class PropertyChangedEventHandlerExtensions { public static void Raise(this PropertyChangedEventHandler onPropertyChanged, object sender, [CallerMemberName] string propertyName = "") { if (onPropertyChanged != null) onPropertyChanged(sender, new PropertyChangedEventArgs(propertyName)); } public static void Raise<PropertyType>(this PropertyChangedEventHandler onPropertyChanged, object sender, Expression<Func<PropertyType>> propertyExpression) { onPropertyChanged.Raise(sender, propertyExpression.GetMemberName()); } static string GetMemberName<MemberType>(this Expression<Func<MemberType>> expression) { return ((MemberExpression)expression.Body).Member.Name; } }
  16. 16. COMU+ こみゅぷらす ViewModelpublic class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; int identifierCount = 0; public int IdentifierCount { get { return identifierCount; } set { if (value != identifierCount) { identifierCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } } int usingCount = 0; public int UsingCount { get { return usingCount; } set { if (value != usingCount) { usingCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } } int classCount = 0; public int ClassCount { get { return classCount; } set { if (value != classCount) { classCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } } int fieldCount = 0; public int FieldCount { get { return fieldCount; } set { if (value != fieldCount) { fieldCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } }
  17. 17. COMU+ こみゅぷらす ViewModel int propertyCount = 0; public int PropertyCount { get { return propertyCount; } set { if (value != propertyCount) { propertyCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } } int methodCount = 0; public int MethodCount { get { return methodCount; } set { if (value != methodCount) { methodCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } } int variableCount = 0; public int VariableCount { get { return variableCount; } set { if (value != variableCount) { variableCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } } int ifCount = 0; public int IfCount { get { return ifCount; } set { if (value != ifCount) { ifCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } }
  18. 18. COMU+ こみゅぷらす ViewModel int lambdaCount = 0; public int LambdaCount { get { return lambdaCount; } set { if (value != lambdaCount) { lambdaCount = value; PropertyChanged.Raise(this); RaiseUpdateData(); } } } public object Data { get { return new [] { new { 名称 = "識別子の数" , 結果 = IdentifierCount }, new { 名称 = "using の数" , 結果 = UsingCount }, new { 名称 = "クラスの数" , 結果 = ClassCount }, new { 名称 = "フィールドの数", 結果 = FieldCount }, new { 名称 = "プロパティの数", 結果 = PropertyCount }, new { 名称 = "メソッドの数" , 結果 = MethodCount }, new { 名称 = "変数の数" , 結果 = VariableCount }, new { 名称 = "if の数" , 結果 = IfCount }, new { 名称 = "ラムダ式の数" , 結果 = string result = string.Empty; public string Result { get { return result; } set { if (value != result) { result = value; PropertyChanged.Raise(this); } } } public void Clear() { IdentifierCount = UsingCount = ClassCount = FieldCount = PropertyCount = MethodCount = VariableCount = IfCount = LambdaCount = 0; Result = string.Empty; } void RaiseUpdateData() { PropertyChanged.Raise(this, () => Data); } } }
  19. 19. COMU+ こみゅぷらす Roslyn を用いたコード解析部 • Roslyn.Compilers.CSharp.SyntaxWalker クラスを継承 • SyntaxWalker クラス – Visitor パターン – Visit メソッドを呼ぶと、全ノードを辿 り、ノードの種類毎の virtual メソッド を呼ぶ • 例えば、識別子のノードの場合には、 VisitIdentifierName という virtual メソッ ドが呼ばれる • それぞれの virtual メソッドをオーバーライ ドすれば、そこに処理を書ける • 今日は、呼ばれた回数を数えるだけ
  20. 20. COMU+ こみゅぷらす Roslyn を用いたコード解析部 using Roslyn.Compilers.CSharp; using System.IO; using System.Text; namespace AddinByRoslyn { class SyntaxCounter : SyntaxWalker { readonly ViewModel viewModel; StringBuilder stringBuilder; // viewModel.Result 用 public SyntaxCounter(ViewModel viewModel) { this.viewModel = viewModel; } // ソース ファイルの中を解析 public void AnalyzeSourceFile(string sourceFileName) { using (var reader = new StreamReader(sourceFileName, false)) { var sourceCode = reader.ReadToEnd(); Analyze(sourceCode); } }
  21. 21. COMU+ こみゅぷらす Roslyn を用いたコード解析部 // ソース コードの中を解析 void Analyze(string sourceCode) { // Roslyn.Compilers.CSharp.SyntaxTree クラスによるシンタックス ツリーの取得 var tree = SyntaxTree.ParseText(sourceCode); Analyze(tree.GetRoot()); // シンタックス ツリーのルート要素を解析 } // ルート要素の中を解析 void Analyze(CompilationUnitSyntax root) { viewModel.Clear(); stringBuilder = new StringBuilder(); Visit(root); // Visit メソッドにより、全ノードを辿る (Visitor パターン) viewModel.Result = stringBuilder.ToString(); } // 全ノードについて public override void DefaultVisit(SyntaxNode node) { base.DefaultVisit(node); // ノードの情報を stringBuilder に追加 stringBuilder.AppendLine(string.Format("NodeType: {0}, Node: {1}", node.GetType().Name, node.GetText())); }
  22. 22. COMU+ こみゅぷらす Roslyn を用いたコード解析部// 識別子のノードの場合 public override void VisitIdentifierName(IdentifierNameSyntax node) { base.VisitIdentifierName(node); viewModel.IdentifierCount++; // 識別子を数える } // using のノードの場合 public override void VisitUsingDirective(UsingDirectiveSyntax node) { base.VisitUsingDirective(node); viewModel.UsingCount++; // using を数える } // クラスのノードの場合 public override void VisitClassDeclaration(ClassDeclarationSyntax node) { base.VisitClassDeclaration(node); viewModel.ClassCount++; // クラスを数える } // フィールドのノードの場合 public override void VisitFieldDeclaration(FieldDeclarationSyntax node) { base.VisitFieldDeclaration(node); viewModel.FieldCount++; // フィールドを数える }
  23. 23. COMU+ こみゅぷらす Roslyn を用いたコード解析部 // プロパティのノードの場合 public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) { base.VisitPropertyDeclaration(node); viewModel.PropertyCount++; // プロパティを数える } // メソッドのノードの場合 public override void VisitMethodDeclaration(MethodDeclarationSyntax node) { base.VisitMethodDeclaration(node); viewModel.MethodCount++; // メソッドを数える } // 変数のノードの場合 public override void VisitVariableDeclaration(VariableDeclarationSyntax node) { base.VisitVariableDeclaration(node); viewModel.VariableCount++; // 変数を数える } // if のノードの場合 public override void VisitIfStatement(IfStatementSyntax node) { base.VisitIfStatement(node);
  24. 24. COMU+ こみゅぷらす Roslyn を用いたコード解析部 // シンプルなラムダ式のノードの場合 public override void VisitSimpleLambdaExpression(SimpleLambdaExpressionSyntax node) { base.VisitSimpleLambdaExpression(node); viewModel.LambdaCount++; // ラムダ式を数える } // 括弧付きのラムダ式のノードの場合 public override void VisitParenthesizedLambdaExpression(ParenthesizedLambdaExpressionSyntax node) { base.VisitParenthesizedLambdaExpression(node); viewModel.LambdaCount++; // ラムダ式を数える } } }
  25. 25. COMU+ こみゅぷらす View.xaml • XAML の Grid 内 – ViewModel の Result を表示するための TextBox – ViewModel の Data を表示するための DataGrid • プロジェクトに System.Xaml への参照設定を追 加
  26. 26. COMU+ こみゅぷらす View.xaml <Window x:Class="AddinByRoslyn.View" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="500" d:DesignWidth="500"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBox TextWrapping="Wrap" Text="{Binding Path=Result}" FontFamily="Meiryo" FontSize="14" IsReadOnlyCaretVisible="True" VerticalScrollBarVisibility="Auto" /> <DataGrid Grid.Row="1" ItemsSource="{Binding Path=Data}" FontFamily="Meiryo" FontSize="14" /> </Grid> </Window>
  27. 27. COMU+ こみゅぷらす View.xaml.cs • ViewModel のインスタンスを保持 – DataContext • コンストラクターで C# のソース ファイル名を 受け取る – SyntaxCounter クラスで解析
  28. 28. COMU+ こみゅぷらす View.xaml.cs using System.Windows; namespace AddinByRoslyn { public partial class View : Window { ViewModel viewModel = new ViewModel(); public View(string sourceFileName) { InitializeComponent(); DataContext = viewModel; // DataContext に ViewModel のインスタンスを設定 if (!string.IsNullOrWhiteSpace(sourceFileName)) // SyntaxCounter クラスを用いたソース ファイルの解析 new SyntaxCounter(viewModel).AnalyzeSourceFile(sourceFileName); } } }
  29. 29. COMU+ こみゅぷらす • ViewModel のインスタンスを保持 – DataContext • コンストラクターで C# のソース ファイル名を 受け取る – SyntaxCounter クラスで解析
  30. 30. COMU+ こみゅぷらす Visual Studio アドイン部 • Visual Studio アドイン部のコード をカスタマイズ –プロジェクトの新規作成時に自動生成 された Connect.cs 内 –Exec メソッドの中で View を作成し、 ソースコード ファイル名を渡す
  31. 31. COMU+ こみゅぷらす Visual Studio アドイン部 // カスタマイズする Exec メソッド public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled) { if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault && commandName == "AddinByRoslyn.Connect.AddinByRoslyn") { var view = new View(GetSourceFileName()); // View のインスタンスにソースファイル名を渡す view.Show(); handled = true; } else { handled = false; } } // ソース ファイル名の取得 (追加する private メソッド) string GetSourceFileName() { var items = _applicationObject.SelectedItems; if (items.Count == 0) return null; var item = items.Item(1); return item.ProjectItem.get_FileNames(1); }
  32. 32. COMU+ こみゅぷらす 実行結果
  33. 33. COMU+ こみゅぷらす 実行結果
  34. 34. COMU+ こみゅぷらす まとめ • 今日は、Roslyn を使って何種類かの文法要素を 数えただけ • 同様の方法で、より複雑な解析を行ったり、一 部を変更できる • Roslyn の機能は C# や Visual Basic のソース コードの解析だけではない
  35. 35. COMU+ こみゅぷらす
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×