Successfully reported this slideshow.
Your SlideShare is downloading. ×

.NET Compiler Platform

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 62 Ad

More Related Content

Slideshows for you (20)

Viewers also liked (20)

Advertisement

Similar to .NET Compiler Platform (20)

More from 信之 岩永 (19)

Advertisement

Recently uploaded (20)

.NET Compiler Platform

  1. 1. Compiler Platform コード解析とC#の未来 C# とともに祝15周年 岩永信之
  2. 2. 今日話すこと • 2015世代でC#チームが提供するもの • C# 6.0 • .NET Compiler Platform • それがもたらす影響 • 独自のアナイライザー作成 • Code-Aware Library • 課題 • C# 7.0以降にどうつながるか
  3. 3. C# 6.0 .NET Compiler Platform .NETチーム、C#チームが提供する“現状”
  4. 4. C# 6.0 • 自動プロパティの改善 • expression-bodied関数メンバー • 文字列補間 • nameof演算子 • null条件演算子 • using static • 例外フィルター • catch/finally句内でのawait 等々 正直なところ華はない • 機能追加よりも優先すべき ことがあった • 限られた時間の中で “2015”に間に合うもの
  5. 5. C# 6.0 • 自動プロパティの改善 • expression-bodied関数メンバー • 文字列補間 • nameof演算子 • null条件演算子 • using static • 例外フィルター • catch/finally句内でのawait 等々 正直なところ華はない • 機能追加よりも優先すべき ことがあった • 限られた時間の中で “2015”に間に合うもの C# 6.0の話は今日はほぼしません 既存資料※をご覧ください ※ http://ufcpp.net/study/csharp/ap_ver6.html http://www.slideshare.net/ufcpp/csharp6 IDE前提の機能 .NET Compiler Platform
  6. 6. IDE前提の機能 • nameof演算子 • 識別子名を文字列として取得できる機能 • 識別子でないものはnameofの中に書けない • 修正漏れとかをコンパイル エラーにできる • IDEの中で真価を発揮 • 修正漏れがあればリアルタイムに気付ける • リファクタリングの対象になる • 識別子のリネームに追従する nameof(x) == "x" コンパイルするだけなら ほぼただの文字列リテラル
  7. 7. Demo https://github.com/ufcpp/UfcppSample/tree/master/Demo/2015/CompilerPlatform/NameofDemo
  8. 8. プログラミング言語のIDE連携 • C# = IDEの恩恵を強く受けれる言語 • (今までも)リアルタイム解析 常にバックグラウンドで解析走ってる • 「ビルド」操作した時のコンパイル時間短い • コンパイル時よりももっと早い段階で、常にどこに問題があるかわかる • (今、さらに)nameof演算子でこの傾向が強まる "x" : 文字列の中の意味をコンパイラーは知らない 実行してみて初めて問題がわかる nameof(x) : ()の中の意味をコンパイラーが知ってる リアルタイム解析の対象
  9. 9. .NET Compiler Platform • C#コンパイラーを1から作り直した • コードネーム“Roslyn”、製品名“.NET Compiler Platform” • 単なるコンパイラーではなく、プラットフォーム化 旧 source executable 新 source executable ブラックボックス 出力しか取れない ホワイトボックス化 中間データを取れるように • 抽象構文木の取得・書き換え • 拡張性の提供誰でもIDEと連携できる
  10. 10. プラットフォーム化が最優先 • C# 6.0(機能追加) < 作り直し(プラットフォーム化) • 作り直しで手いっぱいで大きいことまでできない • (作り直して保守が楽になったからこそ細かいことができる) • C# 6.0 • 悪く言えば、おまけ、華がない • 良く言えば、そんな大変な中よく新機能を2015に間に合わせた 実はおまけ
  11. 11. Compiler Platform 誰でもコンパイラーの中身に触れられる 誰でもIDE連携できる まず、「作る側」の話
  12. 12. コード解析(Visual Studio標準) コンパイルはできるんだけど、 人的ミスっぽいものを警告 アイテム テンプレートには多めに 出しておいて、最後に整理して消す 人それぞれで流儀が違うけど、 プロジェクト内ではそろえたい
  13. 13. コード解析(Visual Studio標準) 緑の下線(警告): 可能な限り直すべきもの 半透明(情報): 問題はないけども、直しようがあるもの using System
  14. 14. コード解析(Visual Studio標準) • クイック アクション 直しようがあるものには 直し方も提示、自動修正 電球マークが目印) 一斉修正 ドキュメント内全部 プロジェクト内全部 ソリューション内全部 (
  15. 15. デモ
  16. 16. プラットフォーム化 • こういうコード解析を誰でも作れるように • 作れるもの: • アナライザー(analyzer) • シンボル追加、メソッド追加、コンパイル時などのタイミングで • コードを解析して、エラー/警告/情報 を出す • コード修正(code fix) • 特定の エラー/警告/情報 に反応して • 修正方法を提示して • その場限り、ファイル内全部、プロジェクト内全部、ソリューション内全部 などをまとめて修正
  17. 17. コード解析の自作に必要なもの(1) • Visual Studio 2015 SDK • 「Visual Studio SDK」とかで検索、ダウンロード https://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs.aspx
  18. 18. コード解析の自作に必要なもの(2) • .NET Compiler Platform SDK Template • 「拡張機能と更新プログラム」で「.NET Compiler」とかで検索
  19. 19. コード解析の自作 • テンプレート → Extensibility → Analyzer with Code Fix
  20. 20. デモ コード解析本体 テスト Visual Studio拡張 (NuGetパッケージが作られる) (F5実行でVisual Studioをデバッグ起動) テンプレ通りの状態で アナライザーとコード修正が1つずつ
  21. 21. 配布 • VSIX (Visual Studio Extension※)形式 • Visual Studioにインストール • 全プロジェクトから使う • Visual Studio Galleryで検索・ダウンロード可能† • NuGet形式 • プロジェクト単位で参照 • 使う・使わないをプロジェクトごとに切り替え • ライブラリと同梱で配布可能 • NuGet Galleryで検索・ダウンロード可能† ※ VSI (Visual Studio Installer)の流れを組んでるからVSIXと言うみたい ファイル構造的には必要なファイルをZIPで固めただけ † もちろん、VSIX/NuGetパッケージをファイル配布してもOK
  22. 22. 配布: Visual Studio Gallery Webサイト Visual Studio上から検索
  23. 23. 配布: NuGet Gallery Webサイト Visual Studio上から検索
  24. 24. 拡張である意味 • Visual Studio/C#コンパイラー標準でない意味 • 特定分野の限定機能も提供できる ⇔ 汎用 • 実装方法をカスタマイズできる ⇔ 汎用性と利便性は両立しにくい • 時代遅れになったら辞めればいい ⇔ 足すより減らす方が難しい • 経験則的な機能※も提供できる ⇔ 確実な機能しか提供できない • 嫌なら使わなければいい ⇔ 嫌でも使わされる • ライブラリ固有事情を汲める ⇔ ライブラリのことは知らない コンパイラーは…拡張なら… ※ 端的にいうと誤判定・判定漏れもあり得る
  25. 25. 拡張である意味 • Visual Studio/C#コンパイラー標準でない意味 • 特定分野の限定機能も提供できる ⇔ 汎用 • 実装方法をカスタマイズできる ⇔ 汎用性と利便性は両立しにくい • 時代遅れになったら辞めればいい ⇔ 足すより減らす方が難しい • 経験則的な機能※も提供できる ⇔ 確実な機能しか提供できない • 嫌なら使わなければいい ⇔ 嫌でも使わされる • ライブラリ固有事情を汲める ⇔ ライブラリのことは知らない コンパイラーは…拡張なら… ※ 端的にいうと誤判定・判定漏れもあり得る Code-Awareライブラリ Code-Aware: (ライブラリ利用側の)「コードまで理解する」「コードを意識した」 • ライブラリ固有の事情にそったアナライザーを • ライブラリ本体と同梱して配布
  26. 26. プラットフォーム化の可能性 「作る側」になる人は多くない 一般開発者への恩恵は何か 「使う側」の話
  27. 27. 作る人 <<[壁]<< 使う人 • 「誰でも作れる」≠「誰もが作る」 • 実際とのところ、作る人は少数 • だいたい、作るの結構大変 • 一度作ったらしばらく手を入れずに使い続けれる • 誰かが作って、みんなが使う • プラットフォームには上モノが乗って初めて価値が出る • 「PCはアプリがなければただの箱」と同じ理屈 作りやすくなる → 作られる → 使う人が便利に ここまで揃って初めて 「目玉機能」になる
  28. 28. いくつか紹介 • 「ただの箱」でないところを紹介 • 現時点での話 • まだまだスタート地点に立ったばかり • CTPまでは変更が多くて追いにくかったし、RCが出てまだ1・2ヶ月 • たまに、Galleryを検索してみるといいと思う • おおまかに分類 • コード解析系 • Code-Awareライブラリ系 • メタプログラミング系
  29. 29. いくつか紹介 What 何をしてくれるものか Why どうしてC#コンパイラー/VSの標準機能にならないのか どうしてライブラリ+アナライザーなのか Owner 拡張ツールの作者(中心人物、会社、チーム)
  30. 30. コード解析系 • 単純に静的コード解析+リファクタリング
  31. 31. C# Essentials What C# 5.0を6.0化するのをガイドしてくれる 主に ?. と => Why C# 5.0→6.0の移行期にしか要らない 古い形式のままで使いたい人もいる Owner Dustin Campbell (C#/VBチームのプログラム マネジャー) https://github.com/DustinCampbell/CSharpEssentials
  32. 32. C# Essentials What C# 5.0を6.0化するのをガイドしてくれる 主に ?. と => Why C# 5.0→6.0の移行期にしか要らない 古い形式のままで使いたい人もいる Owner Dustin Campbell (C#/VBチームのプログラム マネジャー) https://github.com/DustinCampbell/CSharpEssentials
  33. 33. StyleCop Analyzer What StyleCopが提供していたコード解析機能をVS拡張に Why 趣味を選ぶ(人によって流儀が違う) 指示が細かすぎる Owner Sam Harwell Coverity (静的解析ツール ベンダー)社員、MS MVP https://github.com/DotNetAnalyzers/StyleCopAnalyzers
  34. 34. NRefactory 6 What NRefactory (SharpDevelopのコード解析)がRoslyn実装に (MonoDevelopのコード解析もNRefactory) Why SharpDevelopチームが主導 VS標準よりも細かい指示多め Owner SharpDevelopチーム https://visualstudiogallery.msdn.microsoft.com/68c1575b-e0bf-420d-a94b-1b0f4bcdcbcc
  35. 35. Code Cracker What コミュニティ ベースでいくつかの便利機能を実装 var強制、Regexの静的解析など Why コミュニティを中心に開発 趣味を選ぶ Owner 数名のMS MVP https://github.com/code-cracker/code-cracker
  36. 36. Code-Awareライブラリ系 • ライブラリ固有事情を汲み取り • そのライブラリ以外にとっては役に立たないコード解析 • 現状、あんまりいいのが見つからなかったので自作のを紹介
  37. 37. (デモ用) FluentArithmetic What デモ用に、最低限の機能に絞ったCode-Awareライブラリ 1.Add(2).Mul(3)みたいな書き方で整数四則演算 Why .Dive(0)を認めないとか1.Add(2)を3に修正したりとか このライブラリ以外でまったく役に立たない Owner 自作 https://github.com/ufcpp/UfcppSample/tree/master/Chapters/DevEnv/CodeAwareLibrarySample
  38. 38. (デモ用) FluentArithmetic What デモ用に、最低限の機能に絞ったCode-Awareライブラリ 1.Add(2).Mul(3)みたいな書き方で整数四則演算 Why .Dive(0)を認めないとか1.Add(2)を3に修正したりとか このライブラリ以外でまったく役に立たない Owner 自作 https://github.com/ufcpp/UfcppSample/tree/master/Chapters/DevEnv/CodeAwareLibrarySample 0割りエラー リテラル同士の演算を短縮
  39. 39. LazyMixin What 構造体を他の型に埋め込んで使う has-aな実装で、is-a的な体験を提供 Why ライブラリだけで縛れない規約が多すぎる ダメな書き方をエラーに、推奨の書き方をコード生成 Owner 自作 https://github.com/ufcpp/LazyMixin もっと汎用的な仕組みに書き換え中: https://github.com/ufcpp/MixinGenerator
  40. 40. LazyMixin What 構造体を他の型に埋め込んで使う has-aな実装で、is-a的な体験を提供 Why ライブラリだけで縛れない規約が多すぎる ダメな書き方をエラーに、推奨の書き方をコード生成 Owner 自作 https://github.com/ufcpp/LazyMixin もっと汎用的な仕組みに書き換え中: https://github.com/ufcpp/MixinGenerator readonlyがついていると意図しない動作になるのでエラーにする 推奨の使い方をコード生成
  41. 41. 他にこんな使い方できそう • JSONライブラリで、文字列リテラル中のJSON解析を同梱 • LINQ Providerに「使える式は何」警告機能を付ける。
  42. 42. メタプログラミング系 • コード修正というより、コード生成 • アナライザー実装にすることで • コード生成元もC# ⇔ T4テンプレート: 元がキモイ • コード生成結果が見える ⇔ PostSharpなど: 生成結果が見えない • 現状、あんまりいいのが見つからなかったので自作等を紹介 わかりやすさ大事。特に、継続的に保守する場合 見えないとデバッグが大変。何が原因か追えない
  43. 43. NotifyPropertyChangedGenerator What INotifyPropertyChanged実装をコード生成 Why 特定用途すぎるし、実装方法にバリエーションがある 手書きがむちゃくちゃ大変 Owner neuecc (MS MVP) https://github.com/neuecc/NotifyPropertyChangedGenerator
  44. 44. NotifyPropertyChangedGenerator What INotifyPropertyChanged実装をコード生成 Why 特定用途すぎるし、実装方法にバリエーションがある 手書きがむちゃくちゃ大変 Owner neuecc (MS MVP) https://github.com/neuecc/NotifyPropertyChangedGenerator
  45. 45. RecordConstructorGenerator What immutableな型のコンストラクターを書くのだるいので コード生成するようにした Why C#ができた当初(15年前)には考慮に欠けてた C# 7.0で状況改善しそうだけども、それまでのつなぎに Owner 自作 https://github.com/ufcpp/RecordConstructorGenerator
  46. 46. RecordConstructorGenerator What immutableな型のコンストラクターを書くのだるいので コード生成するようにした Why C#ができた当初(15年前)には考慮に欠けてた C# 7.0で状況改善しそうだけども、それまでのつなぎに Owner 自作 https://github.com/ufcpp/RecordConstructorGenerator
  47. 47. 将来の話 まだまだ始まったばかりで課題だらけ これから充実させていってほしいものもある C# 7.0
  48. 48. IDE連携 ≠ Visual Studio連携 • Q. で、Visual Studio以外で使えるの? • A. Roslynオープンソース化の意味がここで強く効いてくる • 現状、Visual Studioのみだけど • Xamarin Studio : 対応中みたい • OmniSharp : Roslyn化フォークがある、作業中 • ATOM, Emacs, Sublime Text, Vim, ... • Visual Studio Code : ATOM実装(コード解析はOmniSharp任せ)
  49. 49. 難易度: 「可能にはなった」程度 • コンパイラーの中身に触れるようになっただけ var props = propertyNames.Select(p => new Property(p)).ToArray(); var docComment = GenerateDocComment(props.Select(p => p.Name)); var parameterList = ParameterList().AddParameters(props.Select(p => p.ToParameter()).ToArr var body = Block().AddStatements(props.Select(p => p.ToAssignment()).ToArray()); return ConstructorDeclaration(typeName) .WithModifiers(SyntaxTokenList.Create(PublicToken)) .WithParameterList(parameterList) .WithLeadingTrivia(docComment) .WithBody(body) .WithAdditionalAnnotations(Formatter.Annotation); • 読めた代物じゃない • 書くのも大変 /// <summary>Record Constructor</summary> /// <param name="name"><see cref="Name"/></param> /// <param name="x"><see cref="X"/></param> /// <param name="y"><see cref="Y"/></param> public Point(string name = default(string), int x = default(int), int y = default(int)) { Name = name; X = x; Y = y; }
  50. 50. 解析用の新構文が欲しい • 型のパターン マッチング構文が欲しい • C# 7.0で入りそう(確度高め) • ぶっちゃけ、“内需”だと思う var id = statement.Left as IdentifierNameSyntax; if (id == null) continue; if (id.Identifier.Text == p.Name) return; 特定の型の場合だけ処理アナライザーを書いているとこういうコードだらけに if (statement.Left is IdentifierNameSyntax id && id.Identifier.Text == p.Name) return; C# 7.0 提案 パターン マッチ is演算子の拡張
  51. 51. 構文欲しい 修正用 式ツリー • 組み換え可能な、Roslyn版式ツリーが求められる • 要望としては出ているものの、構文の具体案なし AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(Name.Upper), IdentifierName(Name.Lower))); 「X = x」みたいなものを 作るだけでこの大変さ `${Name.Upper} = ${Name.Lower};` こういう類のメタプログラミング構文が欲しい(この構文は適当)
  52. 52. 参照がめんどくさい • 普通のライブラリの参照方法 • アナライザーの参照 ファイル を参照 プロジェクト を参照 NuGetパッケージ を参照 ※ ※ NuGet参照するには、NuGetのstartupスクリプトに参照設定を書かなきゃ行けない (アナライザー作成テンプレートには最初からそういう設定スクリプトが書かれてる) ファイル を参照 プロジェクト を参照 NuGetパッケージ を参照
  53. 53. メタプログラミングはまだ妥協的 • メタプログラミングでは • 生成元・生成結果両方見えてほしい • ただ、元と結果は明確に分離したい public class Sample1 { public string Name { get; set; } public int X { get; set; } public int Y { get; set; } } public class Sample1 : INotifyPropertyChanged { public int X { get { return x; } set { SetProperty(ref x, value, xPropertyChangedEventA public int Y { get { return y; } set { SetProperty(ref y, value, yPropertyChangedEventA #region NotifyPropertyChangedGenerator public event PropertyChangedEventHandler PropertyChanged; private int x; private static readonly PropertyChangedEventArgs xPropertyChangedEventArgs = new Proper private int y; private static readonly PropertyChangedEventArgs yPropertyChangedEventArgs = new Proper 元情報 生成結果 • デバッグのためだけに見たい • コードを書く上ではノイズ
  54. 54. コンパイラーの負の遺産 • Visual Studio/C#コンパイラー標準でない意味(再掲、抜粋) • 時代遅れになったら辞めればいい ⇔ 足すより減らす方が難しい • 経験則的な機能※も提供できる ⇔ 確実な機能しか提供できない • C# 7.0 提案 • null非許容参照型 • メソッド コントラクト コンパイラーは…拡張なら… この辺りの制限がきつくて足せない機能がある • 互換性を崩さないのが無理 • 100%確実な判定が無理
  55. 55. null非許容参照型 • 今のC#に欠けているもの 値型 参照型 許容 T? T 非許容 T これがない static void F(string s) { if (s == null) throw new ArgumentNullException(nameof(s)); } 現状の書き方 メソッドのシグネチャだけ見て null許容かどうか判定できない 煩雑
  56. 56. null非許容参照型 • 今のC#に欠けているもの 値型 参照型 許容 T? T? 非許容 T T! null非許容参照型 static void F(string! s) { } C# 7.0 提案の書き方 • 誰が見てもnull非許容 • nullチェックはコンパイラー生成
  57. 57. null非許容参照型と互換性問題 • F(string s) を F(string! s) に変えると、利用側を壊す • 今までnullチェックをサボっていた人がいたら • 例外catchで済ませている人がいたら • 標準ライブラリにちゃんと ! が付いてないと利便性半減 互換性と利便性にトレードオフ
  58. 58. null非許容参照型と確実性 • 一時的にnullになっていないといけない場面がある • 配列とか • 特に、コレクションの実装とかで • List<T> • HashSet<T> • この性質と、マルチスレッド動作が合わさると判定不能 var array = new string[N]; for (var i = 0; i < N; i++) { array[i] = ""; } この間は絶対にnull 最初に大きめの配列をとっておいて、そのうちNマスだけ使う
  59. 59. null非許容参照型のアナライザー実装 • アナライザーでなら実装簡単 • 互換性が必要な場面では使わなければいい • 誤判定のリスク<ないことによる不便 • 事実、実装がある • 今でも、ReSharperとかの静的解析ツールはやってる • C#チームも、一度アナライザーで実装してみてる • 実装: https://github.com/mattwar/nullaby • その報告: https://github.com/dotnet/roslyn/issues/2119 • もしかしたら、C# 7.0はこのまま、一部アナライザー実装にな るかも
  60. 60. 言語機能のアナライザー実装の課題 • 一部分だけアナライザー? • string! ←こういう書き方を解釈するのはコンパイラー機能 • string! の非nullを解析するのはアナライザー • 機能がon/offできるコンパイラー機能? • 同じバージョンのC#を使っているはずでも、コンパイルできる環境と できない環境ができる 挙動的にはかなりキモい
  61. 61. まとめ
  62. 62. まとめ • C# 6.0、Compiler Platform • IDEとの連携性が実は主役、C# 6.0はちょい役 • Platform化の恩恵 • 皆が作れる • Code-Awareである • ライブラリ固有の事情をくめる • 経験則 • 特定文脈によった解析とか、誤判定(判定漏れ)が許容されうる • C#公式機能ですらアナライザーベースになるかも • null非許容参照型 (あとたぶん、メソッド コントラクトも)

Editor's Notes

  • https://github.com/ufcpp/UfcppSample/
  • こういう機能が今までなかったのも、コンパイラー単品で見たらそんなに意味のある機能じゃないから。
    一方で、ないことに不満を感じられるのはIDEの恩恵を受けてコード書いてきてるから。
    IDE使わない文化の人だと、grep置換が割りかし当たり前に行われてる = リテラル中かどうかはあんまり関係ない
  • 今まで実行時だったエラーがコンパイル時にわかるって意味では、$"" (string interpolation)も同様。
    C# 6.0はIDE連携度が上がってる。
  • まあ、「プラットフォーム化」の着手は実は2008(C# 4.0)とかの世代にはもう始まっていたので、
    悪く言えば、「2015年まで待たされた」「やっと来た」だったりはする。
  • プラットフォーム化(誰でも触れるようにする化)以前の問題として、
    こういう処理のためにコンパイラー(とVisual Studioが使うコード解析)で二重開発してたという問題(負担)もあった。
    二重開発は、保守コストが上がるという問題もあるし、「コンパイラー的には動くはずなのに、IDE上ではエラーに見える」みたいなことも起こりえる
    (C#/Visual Studioではユーザーに見えたことないけど、Java/Eclipseとかでは普通にあった話)。
  • 未使用変数警告は昔からある (全体的に、警告出るまでのリアルタイム度合いは上がった気がする。昔は結構コンパイルするまで出なかった)
    using整理は2013にもあるんだけど、未使用なものが半透明になるのは2015で初。 Resharperとか入れてるとResharperが色変えてた気もする。一斉修正も初。
    this整理は完全に初。
  • Ctrl+.
    とりあえずドット打っとけ
  • 2015で初めてのもの:
    「情報」で半透明表示
    this. の簡略化

    警告出るまでのラグが減ってる気はする。前はビルドするまで出なかったり。
  • 正直、VSのデバッグ起動(もう1インスタンス立ち上がって、元のVSからアタッチ)、ものすごい遅いんでストレスフル。
    可能な限り「テスト」でなんとかして、DLLとかNuGetパッケージを作ったのを参照するほうが楽かも。
    ついでだから、NuGetパッケージをローカルのフォルダーに置いて、それを参照する方法もデモしとこう。
  • まあ、問題もあって。
    アナライザーに絞って検索するすべがないんで、増えてるんだか増えてないんだかわかんない。
  • クライアントUIエンジニアはほんとに困ってるんだけど、逆に、サーバー側エンジニアにとっては無用。この温度感の差も結構問題になる。
    バリエーションは、「値が変化」の判定をどうするかで、EqulityComparer使う、ReferenceEquals使う、そもそも比較とかせず常にイベント飛ばすとかある。
    ちゃんと、NotifyPropertyChangedGeneratorではオプション指定できる作りにした(ノイエさんとこはEqualityComparerだったらしく、元はそれ固定だった。うちはReferenceEqualsか、比較なしか。なので、直してpull-req送るなど)。
  • クライアントUIエンジニアはほんとに困ってるんだけど、逆に、サーバー側エンジニアにとっては無用。この温度感の差も結構問題になる。
    バリエーションは、「値が変化」の判定をどうするかで、EqulityComparer使う、ReferenceEquals使う、そもそも比較とかせず常にイベント飛ばすとかある。
    ちゃんと、NotifyPropertyChangedGeneratorではオプション指定できる作りにした(ノイエさんとこはEqualityComparerだったらしく、元はそれ固定だった。うちはReferenceEqualsか、比較なしか。なので、直してpull-req送るなど)。

×