Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
C# 6.0
C# とともに祝15周年
岩永信之
数年待った新仕様
• async/awaitの情報が出始める
• Visual Studio 2012でC# 5.0正式リリース
• C# 6.0の情報が出始める
• C# 7.0の提案が始まる
• Visual Studio 2015でC# ...
Roslyn (潜伏の理由)
• 新コンパイラー(製品名 .NET Compiler Platform)
• 作り直し
• C++コンパイラーの保守がもうつらい
• Visual Studio拡張と、コンパイラー用のコード2重開発がつらい
• ...
.NET 2015とRoslyn
language toolruntime library ecosystem
C# 6.0/VB 14 Ryu JIT
.NET Native
.NET Fx 4.6
.NET Core 5
Visual St...
C# 6.0
• テーマ(?): Just-do-it (いいからやれよ)
• Roslyn化で手いっぱい → 大きなものが入らない
• 潜伏期間が長すぎた。これ以上待たせたくない
• 大きなものはC# 7.0行き
• Roslynにしたからこ...
C# 7.0 (提案開始、ディスカッション中)
• テーマ
• データ
• Null
• パフォーマンスと信頼性
• コンポーネント化
• 分散コンピューティング
• メタプログラミング
https://github.com/dotnet/ro...
本日はC# 6.0の方のみ
• C# 6.0の新機能
• Deep Dive
• 用途・効能(実測)
• 背景・裏話
自動プロパティの改善 式形式の関数メンバー
using static null条件演算子 文字列挿入
nameof 式 インデ...
プロパティやメソッドの改善
• プロパティやメソッドがだいぶ書きやすく
• 式形式の関数メンバー(expression bodied function members)
• メソッド/演算子(expression bodies on metho...
背景: よくあるコード(1)
• 割と単純な計算
class Calculator
{
public double Square(double x) { return x * x; }
}
背景:よくあるコード(2)
• 子オブジェクトに丸投げ
class Sample1 : Sample
{
Sample _inner;
public override string X() { return _inner.X(); }
}
背景:よくあるコード(3)
• readonlyにするためだけにフィールド定義
class Immutable
{
private readonly int _x;
public int X { get { return _x; } }
pub...
背景:よくあるコード(4)
• 初期化するためだけにフィールド定義
class Root
{
private List<string> _items = new List<string>();
public IList<string> Item...
背景: 共通していえること
• { return ; } うざい
• しかも頻出
public double Square(double x) { return x * x; }
public int X { get { return _x; ...
式形式のメソッド/演算子
• returnステートメント1つだけの場合、=> を使って短縮可能
• ラムダ式と同じルール
public override string X() { return _inner.X(); }
public doub...
式形式のプロパティ/インデクサー
• getter-onlyな場合だけ、同様に => を使って短縮可能
• { get { return ; } } を消せる
public int X { get { return _x; } }
public...
自動プロパティ初期化子
• 自動プロパティに対して初期化子が書けるように
• 明示的なフィールド定義が不要に
class Root
{
private List<string> _items = new List<string>();
publ...
getter-onlyな自動プロパティ
• コンストラクター内でだけ初期化できる自動プロパティ
• { get; } だけ書く
class Immutable
{
private readonly int _x;
public int X { ...
没案: プライマリ コンストラクター
• 当初予定では、もう1つ文法が提案されてた
• C# 7.0で、より高度な新機能に統合予定
• プライマリ コンストラクター(没) → レコード型(7.0)
class Immutable(int x)
...
効能
• どのくらいのインパクトがあるか実測
• 計測用のプログラム:
• https://github.com/ufcpp/UfcppSample/tree/master/Scribble/FindSingleStatementBody
• ...
効能: メソッド統計
全体, 16260
0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
式1つだけ, 8343 それ以外, 7917
0% 10% 20% 30% 40% 50% 60% 70% 80%...
効能: プロパティ統計
全体, 5385
0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%getのみ, 2225 自動実装, 1690 1470
0% 10% 20% 30% 40% 50% 60% 70%...
効能: プロパティ統計
全体, 5385
0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%getのみ, 2225 自動実装, 1690 1470
0% 10% 20% 30% 40% 50% 60% 70%...
using static
• 静的メソッドを、メソッド名だけで呼べるように
• using static構文を使う
using System;
public class Program
{
static void Main()
{
Consol...
using staticの用途(1)
• クラスにあまり意味がないもの
• グローバル関数の代わり
• Mathとかが好例
using static System.Math;
class MathSample
{
double F(int x)...
using staticの用途(2)
• ファクトリ メソッド
• 諸事情あってコンストラクターを公開せず、メソッド越しに作るもの
• Expressionとかが好例
using System.Linq.Expressions;
using s...
元々はC#スクリプト用
• Roslynの最終目標には「C#スクリプト」も入っている
• (手が回っていなくて未実装)
• 自作アプリに組み込んでマクロ実行
• REPL上で1行1行C#ステートメントを実行
• スクリプト実行時限定のつもりで機...
静的プロパティ/非静的クラス
• 静的プロパティ可
• 静的クラスである必要ない
using static System.DateTime;
using static System.Console;
public class Program
{...
拡張メソッド
• 拡張メソッドは、静的メソッドとしては呼べない
• 拡張メソッドとしては使える
LINQでおなじみのEnumerableクラス
Enumerable中の拡張メソッド
拡張メソッドを静的メソッドとしては呼べない
staticが付く理由
• もし、staticを付けないと
• 当初提案では付けなくてもよかった
• 結構極悪なコードを書けてやばかったから修正
using System.Linq;
namespace System
{
public stat...
null条件演算子(null conditional operator)
• ?. で nullチェック + メンバー アクセス
• 左辺が null だったら戻り値に null 伝搬
• ?? と組み合わせるのも有効
string name;...
インデクサー/多段チェック
• ?[] でインデクサーに対しても null チェック可能
• 1つの式で多段チェック可能
var m = team.Units?[0]?.Master;
var unit = team.Units != null...
デリゲート/イベント呼び出し
• ?() とは書けない
• 条件演算子 ? : との区別が構文上難しい
• デリゲートなら、?.Invoke で代用可能
void OnPropertyChanged(string propertyName)
=...
用途
• null許容な文脈と、非null許容な文脈ははっきり分かれる
• 許容する方で活躍するはず
例
一覧画面
A B
(順序・位置などに意味があるような)
一覧画面では「空欄」があり得る
空欄をnullで表したり
C
詳細画面
C
wei...
没案: null非許容
• より重要なのは非nullの方
• 現状のC#ではnullを認めないコードを書くのが大変
• C# 7.0で検討中
void ShowDetail(Unit! unit)
{
...
}
(現状の案)
! で非null...
文字列挿入(string interpolation)
• 文字列整形がだいぶ楽に
• $ から文字列を始める
• {} の中に任意の式が書ける
string.Format("({0}, {1})", x, y);
string.Format(...
複数行
• $@ から始める
• ちなみに逆(@$)はダメ(コンパイル エラー)
Console.WriteLine($@"
x: {x}
y: {y}
");
string.Format化
• コンパイル結果
• 要望多かったのに今まで入れなかった理由は単純に
「ライブラリでできることはライブラリでやれ」
• まさに「just-do-it」の代表格
• Roslynになって保守コストが下がったから入れ...
IFormattable
• IFormatProviderを指定したい場合
• (カルチャー指定などをしたい場合)
• stringじゃなくてIFormattableで受ける
• .NET 4.6/.NET Core 5を必要とする唯一の機能...
nameof式(nameof expression)
• 識別子(変数名、メンバー名、クラス名…)を文字列リテラル化
if (x < 0)
throw new ArgumentException("x must be positive");
i...
nameof式(nameof expression)
• 結構複雑な式も書ける
var now = DateTime.Now;
var x1 = nameof(now.AddHours);
var x2 = nameof(IList<int>....
補足: CallerMemberName
• PropertyChanged用途だと、こんな方法も
• ただし、これでは不十分場合あり
private int _x;
public int X
{
get { return _x; }
set ...
補足: CallerMemberNameでは不十分
• パフォーマンス考えるとよりよい書き方があって
public int X
{
get { return _x; }
set { _x = value; PropertyChanged?.In...
補足: CallerMemberNameでは不十分
• 他のプロパティに依存したプロパティ
public int X
{
get { return _x; }
set { _x = value; OnPropertyChanged(); OnP...
インデックス初期化子
• オブジェクト初期化子内にインデクサーを書ける
• 利点
• オブジェクト初期化子で、プロパティと混ぜれる
• 式になる
• => で使える、フィールド初期化子で使える、式ツリー化できる
var d = new Dict...
light weight dynamic
• 裏にあるストーリーは結構壮大
• 場合によっては、辞書的にプロパティ アクセスしたい
• ライブラリ内がリフレクションだらけになったり
{
"Id": 10,
"Position": { "X": ...
light weight dynamic
• プロパティ アクセスと辞書アクセスを近づける発想
var p = new Point();
p.X = 1;
p.Y = 2;
var d = new Dictionary();
d["X"] = ...
Working with data
• C# 7.0の大きなテーマの1つ
• light weight dynamicはそのはしり
• 7.0にご期待ください
• レコード型、タプル型
「データ」が主役
var d = new Dictiona...
例外フィルター
• 例外 catch に条件を付けれるように
• ちなみに
• C#的には新機能だけど、.NET的には1.0のころから持ってる機能
• C#がそれに対応しただけ
try
{
…
}
catch (Exception ex) wh...
用途: inner exceptionでcatch
static void Main()
{
try
{
RunAsync().Wait();
}
catch (InvalidOperationException)
{
Console.Writ...
用途: inner exceptionでcatch
static void Main()
{
try
{
RunAsync().Wait();
}
catch (AggregateException ae)
when (ae.InnerExce...
用途: 複数種の例外
• 複数種類の例外に対して同じ処理
try
{
…
}
catch (Exception ex)
when (ex is AccessViolationException || ex is FileNotFoundExce...
没案: if
• 当初提案ではifキーワードだった
• {} のちょっとした位置で意味が全く変わるとかちょっと
try
{
}
catch (Exception ex) if (ex.InnerException is IOException)...
catch句、finally句でのawait
AsyncResource asyncResource = null;
try
{
asyncResource = new AsyncResource();
}
catch (Exception e...
今までなかったのは
• yield return
• awaitの発想の元になっているのがyield return
(awaitのコード生成結果はyield returnに近い)
• yield returnはtry-catch-finally...
拡張メソッドでコレクション初期化子
• コレクション初期化子の結果として呼ばれるAddメソッドが
拡張メソッドでもOKに
var points = new List<Point>
{
new Point(3, 4),
};
var points...
今までなかったのは
• コンパイル時間を気にしてのことらしい
• 拡張メソッドの検索はノーコストではない
• といっても、普通の拡張メソッドとそんなにコスト変わらないはず
• VBは昔からできてた
まとめ
• Just-do-it
• Roslyn化に時間をかけすぎたのでコンパクトに
• Roslynになったからこそ保守コストが下がって新機能入れやすく
• ロー コスト・ロー リターンな機能ばかりだけど、確実に便利に
• いくつかは、7....
おまけ
• ここから先、時間が残れば
その他小さな変更
• これまでも、大々的に出てない小さな変更はあった
• 特に、破壊的変更
• Visual C# 2008 Breaking Changes
• Visual C# 2010 Breaking Changes
• Visual...
C# 6.0の破壊的変更(1)
• コンストラクターの再帰循環参照
• 昔: 実行時にスタック オーバーフロー
• C# 6.0: コンパイル エラー
class C
{
public C(int x) : this() { }
public ...
C# 6.0の破壊的変更(2)
• generic型インスタンスに対するlock
• 昔: コンパイル通るものの、値型の場合lockの意味ない
• C# 6.0: class制約が必須に
public void DoSomething<T>(T...
C# 6.0の破壊的変更(3)
• generic型の静的readonlyフィールドに対する書き込み
• 昔: 他の特殊化に対して初期化できる
• C# 6.0: 自分自身だけを初期化できる
public static class Foo<T>...
日本人だけが気づく破壊的変更
• Unicodeの変更の影響
• 昔: カタカナ中点(中黒)OK
• C# 6.0: Unicode側のミスでした。Unicodeが修正したらC#にも影響出ま
した
int x・y = 10;
Console.W...
微妙な新機能(1)
• enumの基底型
• 昔: int, short, long など、キーワードでないとダメ
• C# 6.0: Int32, Int16, Int64 など、System名前空間の型でもOK
enum X : Syste...
微妙な新機能(2)
• オーバーロード解決ルールを改善
• 昔: ラムダ式の型推論、1段は行けてたけど2段は無理だった
• C# 6.0: 2段以上もOK
using System;
class FuncOfFuncTypeInference
...
追悼
• 一瞬、C# 6.0に入る予定だったもの
• 互換性壊れるので取りやめたり
• 引数なしの構造体コンストラクター
• C# 7.0で改めて取り組むことになったり
• プライマリ コンストラクター → レコード型
• 変数宣言式 → パタ...
追悼: 構造体の引数なしコンストラク
ター
• 構造体にも引数なしのコンストラクターを定義できるようにす
るはずだった
• .NETのランタイム レベルでバグがあることが発覚して断念
• Activator.CreateInstance<T>(...
追悼: プライマリ コンストラクター
• 型定義の型名の直後にコンストラクターを1個書けた
• 7.0でレコード型に吸収予定
class Immutable(int x)
{
public int X { get; } = x;
}
class...
追悼: 変数宣言式(declaration expressions)
• 式の途中で変数宣言できた
• 7.0でパターン マッチングと合わせて作り直す予定
while ((var line = Console.ReadLine()) != nu...
Upcoming SlideShare
Loading in …5
×

Deep Dive C# 6.0

63,519 views

Published on

2015/4/11
dotNetConf 2015 Japan with JXUG
https://atnd.org/events/63844
にて登壇。

Published in: Technology
  • Be the first to comment

Deep Dive C# 6.0

  1. 1. C# 6.0 C# とともに祝15周年 岩永信之
  2. 2. 数年待った新仕様 • async/awaitの情報が出始める • Visual Studio 2012でC# 5.0正式リリース • C# 6.0の情報が出始める • C# 7.0の提案が始まる • Visual Studio 2015でC# 6.0正式リリース 2010 2011 2012 2013 2014 2015 潜伏期 • 裏でRoslynを作ってて、言語的な新機能何もなし 久しぶりに楽しい時期
  3. 3. Roslyn (潜伏の理由) • 新コンパイラー(製品名 .NET Compiler Platform) • 作り直し • C++コンパイラーの保守がもうつらい • Visual Studio拡張と、コンパイラー用のコード2重開発がつらい • C#チームが作っているコンパイラーの力を、Visual Studio拡張を作って いるサードパーティ企業・個人開発者が活用できないのがつらい • C#でC#コンパイラーを、VBでVBコンパイラーを • 単一コンパイラーでコンパイルとVisual Studio拡張を • コンパイラーの内部データをとれるAPI公開
  4. 4. .NET 2015とRoslyn language toolruntime library ecosystem C# 6.0/VB 14 Ryu JIT .NET Native .NET Fx 4.6 .NET Core 5 Visual Studio 2015 NuGet .NET 2015 新しいコンパイラー csc.exe/vb.exe コード解析ライブラリ Microsoft.CodeAnalysis Roslyn それぞれ独立 • C# 6.0で.NET Framework 2.0開発とかも可能 • .NET 4.5以上をインストールすればMicrosoft.CodeAnalysis利用可能 • Visual Studio 2012は最初から.NET 4.5
  5. 5. C# 6.0 • テーマ(?): Just-do-it (いいからやれよ) • Roslyn化で手いっぱい → 大きなものが入らない • 潜伏期間が長すぎた。これ以上待たせたくない • 大きなものはC# 7.0行き • Roslynにしたからこそ → 細々とした機能を保守できる • コンパイラー自身がC#製になったから本気出す • 「よくあるパターン」のめんどくささを改善
  6. 6. C# 7.0 (提案開始、ディスカッション中) • テーマ • データ • Null • パフォーマンスと信頼性 • コンポーネント化 • 分散コンピューティング • メタプログラミング https://github.com/dotnet/roslyn/issues/98 この辺りのテーマはC# 6.0で いくつか簡単なものが入ってる
  7. 7. 本日はC# 6.0の方のみ • C# 6.0の新機能 • Deep Dive • 用途・効能(実測) • 背景・裏話 自動プロパティの改善 式形式の関数メンバー using static null条件演算子 文字列挿入 nameof 式 インデックス初期化子 catch/finally内でawait 拡張メソッドでコレクション初期化子 例外フィルター
  8. 8. プロパティやメソッドの改善 • プロパティやメソッドがだいぶ書きやすく • 式形式の関数メンバー(expression bodied function members) • メソッド/演算子(expression bodies on method-like members) • プロパティ/インデクサー(expression bodies on property-like members) • 自動プロパティの改善(auto-property enhancements) • 自動プロパティ初期化子(auto-property initializers) • getter-onlyな自動プロパティ(getter-only auto-properties)
  9. 9. 背景: よくあるコード(1) • 割と単純な計算 class Calculator { public double Square(double x) { return x * x; } }
  10. 10. 背景:よくあるコード(2) • 子オブジェクトに丸投げ class Sample1 : Sample { Sample _inner; public override string X() { return _inner.X(); } }
  11. 11. 背景:よくあるコード(3) • readonlyにするためだけにフィールド定義 class Immutable { private readonly int _x; public int X { get { return _x; } } public Immutable(int x) { _x = x; } }
  12. 12. 背景:よくあるコード(4) • 初期化するためだけにフィールド定義 class Root { private List<string> _items = new List<string>(); public IList<string> Items { get { return _items; } } }
  13. 13. 背景: 共通していえること • { return ; } うざい • しかも頻出 public double Square(double x) { return x * x; } public int X { get { return _x; } } public IList<string> Items { get { return _items; } } public override string X() { return _inner.X(); } 特にこいつなんて、書きたいもの(_x)に対して ノイズ({ get { return ; } })が多すぎ
  14. 14. 式形式のメソッド/演算子 • returnステートメント1つだけの場合、=> を使って短縮可能 • ラムダ式と同じルール public override string X() { return _inner.X(); } public double Square(double x) { return x * x; } public override string X() => _inner.X(); public double Square(double x) => x * x;
  15. 15. 式形式のプロパティ/インデクサー • getter-onlyな場合だけ、同様に => を使って短縮可能 • { get { return ; } } を消せる public int X { get { return _x; } } public int X => _x;
  16. 16. 自動プロパティ初期化子 • 自動プロパティに対して初期化子が書けるように • 明示的なフィールド定義が不要に class Root { private List<string> _items = new List<string>(); public IList<string> Items { get { return _items; } } } class Root { public IList<string> Items { get; private set; } = new List<string>(); }
  17. 17. getter-onlyな自動プロパティ • コンストラクター内でだけ初期化できる自動プロパティ • { get; } だけ書く class Immutable { private readonly int _x; public int X { get { return _x; } } public Immutable(int x) { _x = x; } } class Immutable { public int X { get; } public Immutable(int x) { X = x; } }
  18. 18. 没案: プライマリ コンストラクター • 当初予定では、もう1つ文法が提案されてた • C# 7.0で、より高度な新機能に統合予定 • プライマリ コンストラクター(没) → レコード型(7.0) class Immutable(int x) { public int X { get; } = x; } class Immutable { public int X { get; } public Immutable(int x) { X = x; } } プライマリ コンストラクター(没) 未
  19. 19. 効能 • どのくらいのインパクトがあるか実測 • 計測用のプログラム: • https://github.com/ufcpp/UfcppSample/tree/master/Scribble/FindSingleStatementBody • せっかくなのでMicrosoft.CodeAnalysisライブラリを利用 • 今仕事で使っているソリューションを1個、集計してみた
  20. 20. 効能: メソッド統計 全体, 16260 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% 式1つだけ, 8343 それ以外, 7917 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% 全体のうち51.3% が => 化の恩恵を受ける
  21. 21. 効能: プロパティ統計 全体, 5385 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%getのみ, 2225 自動実装, 1690 1470 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%式1つ, 2101 自動実装, 1690 1470 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%243 1858 372 1318 1470 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% フィールドの値を返すだけ private set 全体のうち39% getのみのプロパティの94.4% が => 化の恩恵を受ける
  22. 22. 効能: プロパティ統計 全体, 5385 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%getのみ, 2225 自動実装, 1690 1470 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%式1つ, 2101 自動実装, 1690 1470 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%243 1858 372 1318 1470 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% フィールドの値を返すだけ private set 合計615個(全体の11.4%)※が 自動プロパティの改善の恩恵受ける ※ public setなものの多くがJSON化の都合でpublic。実際には書き替えしてない
  23. 23. using static • 静的メソッドを、メソッド名だけで呼べるように • using static構文を使う using System; public class Program { static void Main() { Console.WriteLine("hello"); } } using static System.Console; public class Program { static void Main() { WriteLine("hello"); } } System.Console.WriteLine が呼ばれる
  24. 24. using staticの用途(1) • クラスにあまり意味がないもの • グローバル関数の代わり • Mathとかが好例 using static System.Math; class MathSample { double F(int x) => x * Log(x); double G(int x) => Sin(x) * Exp(x); } 数学関数ばっかり使うような文脈で、 1個1個 Math. を付けたくない
  25. 25. using staticの用途(2) • ファクトリ メソッド • 諸事情あってコンストラクターを公開せず、メソッド越しに作るもの • Expressionとかが好例 using System.Linq.Expressions; using static System.Linq.Expressions.Expression; class ExpressionSample { static ParameterExpression x = Parameter(typeof(int)); static ParameterExpression y = Parameter(typeof(int)); static Expression ex = Lambda(Add(x, y), x, y); } Expressionクラスの静的メソッドで インスタンス生成
  26. 26. 元々はC#スクリプト用 • Roslynの最終目標には「C#スクリプト」も入っている • (手が回っていなくて未実装) • 自作アプリに組み込んでマクロ実行 • REPL上で1行1行C#ステートメントを実行 • スクリプト実行時限定のつもりで機能を追加した • あまりにも要望多すぎて、通常のC#にも実装
  27. 27. 静的プロパティ/非静的クラス • 静的プロパティ可 • 静的クラスである必要ない using static System.DateTime; using static System.Console; public class Program { public static void Main() { WriteLine(Now); } } 普通の(static が付かない)クラス (こっちは静的クラス) 静的プロパティ
  28. 28. 拡張メソッド • 拡張メソッドは、静的メソッドとしては呼べない • 拡張メソッドとしては使える LINQでおなじみのEnumerableクラス Enumerable中の拡張メソッド 拡張メソッドを静的メソッドとしては呼べない
  29. 29. staticが付く理由 • もし、staticを付けないと • 当初提案では付けなくてもよかった • 結構極悪なコードを書けてやばかったから修正 using System.Linq; namespace System { public static class Linq { public static string nameof(Action x) => ""; } } 既存の名前空間と同名のクラス 元とは別の定義を紛れ込ませられる 没
  30. 30. null条件演算子(null conditional operator) • ?. で nullチェック + メンバー アクセス • 左辺が null だったら戻り値に null 伝搬 • ?? と組み合わせるのも有効 string name; if (unit == null) name = "空欄"; else name = unit.Master.Name; var name = unit?.Master.Name ?? "空欄"; var name = unit == null ? "空欄" : unit.Master.Name; あるいは
  31. 31. インデクサー/多段チェック • ?[] でインデクサーに対しても null チェック可能 • 1つの式で多段チェック可能 var m = team.Units?[0]?.Master; var unit = team.Units != null ? team.Units[0] : null; var m = unit != null ? unit.Master : null;
  32. 32. デリゲート/イベント呼び出し • ?() とは書けない • 条件演算子 ? : との区別が構文上難しい • デリゲートなら、?.Invoke で代用可能 void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  33. 33. 用途 • null許容な文脈と、非null許容な文脈ははっきり分かれる • 許容する方で活躍するはず 例 一覧画面 A B (順序・位置などに意味があるような) 一覧画面では「空欄」があり得る 空欄をnullで表したり C 詳細画面 C weight : 327 dimension: 14.6×14×3.5 詳細画面では無効な項目 の表示は想定しない タップで 画面遷移 null許容(nullable) 非null (non-nullable)
  34. 34. 没案: null非許容 • より重要なのは非nullの方 • 現状のC#ではnullを認めないコードを書くのが大変 • C# 7.0で検討中 void ShowDetail(Unit! unit) { ... } (現状の案) ! で非nullを明示 ※ 既存のC#コードを壊さないように非null 対応するのはかなり大変で妥協が必要 • 古いコードが混在すると100%の非null 保証は無理 • ! を付ける必要あり 未
  35. 35. 文字列挿入(string interpolation) • 文字列整形がだいぶ楽に • $ から文字列を始める • {} の中に任意の式が書ける string.Format("({0}, {1})", x, y); string.Format("数値: {0:n}, 通貨: {0:c}", x); $"({x}, {y})" $"数値: {x:n}, 通貨: {x:c}" 書式設定も使える
  36. 36. 複数行 • $@ から始める • ちなみに逆(@$)はダメ(コンパイル エラー) Console.WriteLine($@" x: {x} y: {y} ");
  37. 37. string.Format化 • コンパイル結果 • 要望多かったのに今まで入れなかった理由は単純に 「ライブラリでできることはライブラリでやれ」 • まさに「just-do-it」の代表格 • Roslynになって保守コストが下がったから入れれた string.Format("({0}, {1})", x, y); $"({x}, {y})" まんま、string.Formatが生成されるだけ
  38. 38. IFormattable • IFormatProviderを指定したい場合 • (カルチャー指定などをしたい場合) • stringじゃなくてIFormattableで受ける • .NET 4.6/.NET Core 5を必要とする唯一の機能 • FormattableStringは新しく追加された型 • (他は、await除けば.NET 2.0で動く) IFormattable f = $"{x:c}, {x:n}"; var s = f.ToString(null, new CultureInfo("en-us")); FormattableString型の インスタンスが作られる カルチャー指定して文字列化
  39. 39. nameof式(nameof expression) • 識別子(変数名、メンバー名、クラス名…)を文字列リテラル化 if (x < 0) throw new ArgumentException("x must be positive"); if (x < 0) throw new ArgumentException(nameof(x) + " must be positive"); リファクタリングの対象にならない リファクタリングの対象になる • 「リネーム」できる • 「定義に移動」できる • 「参照の検索」できる
  40. 40. nameof式(nameof expression) • 結構複雑な式も書ける var now = DateTime.Now; var x1 = nameof(now.AddHours); var x2 = nameof(IList<int>.Count); var x3 = nameof(System.Text.RegularExpressions.Regex); AddHours Count Regex
  41. 41. 補足: CallerMemberName • PropertyChanged用途だと、こんな方法も • ただし、これでは不十分場合あり private int _x; public int X { get { return _x; } set { _x = value; OnPropertyChanged(); } } void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 自動的に"X"の名前が渡る
  42. 42. 補足: CallerMemberNameでは不十分 • パフォーマンス考えるとよりよい書き方があって public int X { get { return _x; } set { _x = value; PropertyChanged?.Invoke(this, XProperty); } } private static readonly PropertyChangedEventArgs XProperty = new PropertyChangedEventArgs(nameof(X)); 同じインスタンスを使いまわす 方がメモリ効率がいい この場合、CallerMemberName では役に立たない
  43. 43. 補足: CallerMemberNameでは不十分 • 他のプロパティに依存したプロパティ public int X { get { return _x; } set { _x = value; OnPropertyChanged(); OnPropertyChanged(nameof(Sum)); } } public int Y { get { return _y; } set { _y = value; OnPropertyChanged(); OnPropertyChanged(nameof(Sum)); } } public int Sum => X + Y; X, Y の一方でも変化したら Sumの値も変化する この場合、CallerMemberName では役に立たない
  44. 44. インデックス初期化子 • オブジェクト初期化子内にインデクサーを書ける • 利点 • オブジェクト初期化子で、プロパティと混ぜれる • 式になる • => で使える、フィールド初期化子で使える、式ツリー化できる var d = new Dictionary<string, int> { ["X"] = 1, ["Y"] = 2, };
  45. 45. light weight dynamic • 裏にあるストーリーは結構壮大 • 場合によっては、辞書的にプロパティ アクセスしたい • ライブラリ内がリフレクションだらけになったり { "Id": 10, "Position": { "X": 1, "Y": 2 } } <TextBox Text="{Binding Id}" /> <TextBox Text="{Binding Position.X}" /> <TextBox Text="{Binding Position.Y}" /> public int X { set { _x = value; OnPropertyChanged(nameof(X)); } } プロパティ名が キーの辞書
  46. 46. light weight dynamic • プロパティ アクセスと辞書アクセスを近づける発想 var p = new Point(); p.X = 1; p.Y = 2; var d = new Dictionary(); d["X"] = 1; d["Y"] = 2; var p = new Point { X = 1, Y = 2, }; var d = new Dictionary { ["X"] = 1, ["Y"] = 2, }; var d = new Dictionary(); d.$X = 1; d.$Y = 2; var d = new Dictionary { $X = 1, $Y = 2, }; 没 没 一瞬、こういう文法が提案されてた (キモいって言うやつ多すぎるからやめた)
  47. 47. Working with data • C# 7.0の大きなテーマの1つ • light weight dynamicはそのはしり • 7.0にご期待ください • レコード型、タプル型 「データ」が主役 var d = new Dictionary { ["X"] = 1, ["Y"] = 2, }; 低コスト、低リスクなこいつだけが6.0に残った
  48. 48. 例外フィルター • 例外 catch に条件を付けれるように • ちなみに • C#的には新機能だけど、.NET的には1.0のころから持ってる機能 • C#がそれに対応しただけ try { … } catch (Exception ex) when (ex.InnerException is IOException) { … }
  49. 49. 用途: inner exceptionでcatch static void Main() { try { RunAsync().Wait(); } catch (InvalidOperationException) { Console.WriteLine("ここを通ってほしい"); } } static async Task RunAsync() { await Task.Delay(1); throw new InvalidOperationException(""); } 実際にここに来るのは AggregateException もちろんcatchできない
  50. 50. 用途: inner exceptionでcatch static void Main() { try { RunAsync().Wait(); } catch (AggregateException ae) when (ae.InnerExceptions.Any(e => e is InvalidOperationException)) { Console.WriteLine("ここを通ってほしい"); } }
  51. 51. 用途: 複数種の例外 • 複数種類の例外に対して同じ処理 try { … } catch (Exception ex) when (ex is AccessViolationException || ex is FileNotFoundException) { … }
  52. 52. 没案: if • 当初提案ではifキーワードだった • {} のちょっとした位置で意味が全く変わるとかちょっと try { } catch (Exception ex) if (ex.InnerException is IOException) { … } try { } catch (Exception ex) { if (ex.InnerException is IOException) … } 没
  53. 53. catch句、finally句でのawait AsyncResource asyncResource = null; try { asyncResource = new AsyncResource(); } catch (Exception ex) { using (var w = new StreamWriter("log.txt")) await w.WriteAsync(ex.ToString()); throw; } finally { if (asyncResource != null) await asyncResource.DisposeAsync(); } catch句内でawait 用途: • ログ記録 (ファイル書き込みにしろ サーバーに送るにしろ非同期) finally句内でawait 用途: • 非同期Dispose
  54. 54. 今までなかったのは • yield return • awaitの発想の元になっているのがyield return (awaitのコード生成結果はyield returnに近い) • yield returnはtry-catch-finally句内に書けない • 生成されるコードが結構複雑 • 一度すべての例外をcatch→await→再throw的なコードに展開される • catch前のスタックトレースを保ったまま再throwする
  55. 55. 拡張メソッドでコレクション初期化子 • コレクション初期化子の結果として呼ばれるAddメソッドが 拡張メソッドでもOKに var points = new List<Point> { new Point(3, 4), }; var points = new List<Point>(); points.Add(new Point(3, 4)); var points = new List<Point> { { 3, 4 }, }; var points = new List<Point>(); points.Add(3, 4); static class PointExtensions { public static void Add( this IList<Point> list, int x, int y) => list.Add(new Point(x, y)); }
  56. 56. 今までなかったのは • コンパイル時間を気にしてのことらしい • 拡張メソッドの検索はノーコストではない • といっても、普通の拡張メソッドとそんなにコスト変わらないはず • VBは昔からできてた
  57. 57. まとめ • Just-do-it • Roslyn化に時間をかけすぎたのでコンパクトに • Roslynになったからこそ保守コストが下がって新機能入れやすく • ロー コスト・ロー リターンな機能ばかりだけど、確実に便利に • いくつかは、7.0の大きなテーマにつながる機能 • データ: • null: null条件演算子 インデックス初期化子 拡張メソッドでコレクション初期化子
  58. 58. おまけ • ここから先、時間が残れば
  59. 59. その他小さな変更 • これまでも、大々的に出てない小さな変更はあった • 特に、破壊的変更 • Visual C# 2008 Breaking Changes • Visual C# 2010 Breaking Changes • Visual C# Breaking Changes in Visual Studio 2012 • だいたいは以下の類 • 新機能の余波でオーバーロード解決順序変わりました • バグだったのでなおしました • Roslynオープンソース化で、こういう小さな変更も見えやすく なった
  60. 60. C# 6.0の破壊的変更(1) • コンストラクターの再帰循環参照 • 昔: 実行時にスタック オーバーフロー • C# 6.0: コンパイル エラー class C { public C(int x) : this() { } public C() : this(0) { } }
  61. 61. C# 6.0の破壊的変更(2) • generic型インスタンスに対するlock • 昔: コンパイル通るものの、値型の場合lockの意味ない • C# 6.0: class制約が必須に public void DoSomething<T>(T data) { lock (data) { } // << Generates CS0185 } public void DoSomethingElse(SOptions data) { lock (data) { } // << Works fine } public void DoSomething<T>(T data) where T : class { lock (data) { } // Works fine }
  62. 62. C# 6.0の破壊的変更(3) • generic型の静的readonlyフィールドに対する書き込み • 昔: 他の特殊化に対して初期化できる • C# 6.0: 自分自身だけを初期化できる public static class Foo<T> { static Foo() { if (typeof(T) == typeof(int)) { Foo<int>.compute = x => (int)x; } } public static readonly System.Func<double, T> compute; }
  63. 63. 日本人だけが気づく破壊的変更 • Unicodeの変更の影響 • 昔: カタカナ中点(中黒)OK • C# 6.0: Unicode側のミスでした。Unicodeが修正したらC#にも影響出ま した int x・y = 10; Console.WriteLine(x・y);
  64. 64. 微妙な新機能(1) • enumの基底型 • 昔: int, short, long など、キーワードでないとダメ • C# 6.0: Int32, Int16, Int64 など、System名前空間の型でもOK enum X : System.Int32 { A, B, C, }
  65. 65. 微妙な新機能(2) • オーバーロード解決ルールを改善 • 昔: ラムダ式の型推論、1段は行けてたけど2段は無理だった • C# 6.0: 2段以上もOK using System; class FuncOfFuncTypeInference { static void Main() { X(() => () => 10); } private static int X(Func<Func<int>> f) { return f()(); } private static int X(Func<Func<int?>> f) { return f()() ?? 0; } } int か int? か古いコンパイラーは判定できない
  66. 66. 追悼 • 一瞬、C# 6.0に入る予定だったもの • 互換性壊れるので取りやめたり • 引数なしの構造体コンストラクター • C# 7.0で改めて取り組むことになったり • プライマリ コンストラクター → レコード型 • 変数宣言式 → パターン マッチング
  67. 67. 追悼: 構造体の引数なしコンストラク ター • 構造体にも引数なしのコンストラクターを定義できるようにす るはずだった • .NETのランタイム レベルでバグがあることが発覚して断念 • Activator.CreateInstance<T>() が new T() をnullに置き換える struct MyInt { public readonly int Value; public MyInt() { Value = -1; } public MyInt(int value) { Value = value; } } 没
  68. 68. 追悼: プライマリ コンストラクター • 型定義の型名の直後にコンストラクターを1個書けた • 7.0でレコード型に吸収予定 class Immutable(int x) { public int X { get; } = x; } class Immutable(int x) { } 未 未
  69. 69. 追悼: 変数宣言式(declaration expressions) • 式の途中で変数宣言できた • 7.0でパターン マッチングと合わせて作り直す予定 while ((var line = Console.ReadLine()) != null) if (int.TryParse(line, out var x)) (var y = Math.Sin(x)) * y; if (x is string s) { … } else if (x is int n) { … } 未 未

×