69
C# 6.0 C# とともに15周年 岩永信之

Deep Dive C# 6.0

  • Upload
    -

  • View
    9.135

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Deep Dive C# 6.0

C# 6.0

C#とともに祝15周年

岩永信之

Page 2: Deep Dive C# 6.0

数年待った新仕様

• 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を作ってて、言語的な新機能何もなし

久しぶりに楽しい時期

Page 3: Deep Dive C# 6.0

Roslyn (潜伏の理由)

•新コンパイラー(製品名 .NET Compiler Platform)

•作り直し• C++コンパイラーの保守がもうつらい

• Visual Studio拡張と、コンパイラー用のコード2重開発がつらい

• C#チームが作っているコンパイラーの力を、Visual Studio拡張を作っているサードパーティ企業・個人開発者が活用できないのがつらい

• C#でC#コンパイラーを、VBでVBコンパイラーを

• 単一コンパイラーでコンパイルとVisual Studio拡張を

• コンパイラーの内部データをとれるAPI公開

Page 4: Deep Dive C# 6.0

.NET 2015とRoslyn

language toolruntime library ecosystem

C# 6.0/VB 14 Ryu JIT.NET Native

.NET Fx 4.6.NET Core 5

Visual Studio2015

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

Page 5: Deep Dive C# 6.0

C# 6.0

•テーマ(?): Just-do-it (いいからやれよ)• Roslyn化で手いっぱい→ 大きなものが入らない

• 潜伏期間が長すぎた。これ以上待たせたくない

• 大きなものはC# 7.0行き

• Roslynにしたからこそ→ 細々とした機能を保守できる• コンパイラー自身がC#製になったから本気出す

• 「よくあるパターン」のめんどくささを改善

Page 6: Deep Dive C# 6.0

C# 7.0 (提案開始、ディスカッション中)

•テーマ• データ

• Null• パフォーマンスと信頼性

• コンポーネント化

• 分散コンピューティング

• メタプログラミング

https://github.com/dotnet/roslyn/issues/98

この辺りのテーマはC# 6.0でいくつか簡単なものが入ってる

Page 7: Deep Dive C# 6.0

本日はC# 6.0の方のみ

• C# 6.0の新機能

• Deep Dive• 用途・効能(実測)

• 背景・裏話

自動プロパティの改善 式形式の関数メンバー

using static null条件演算子 文字列挿入

nameof式 インデックス初期化子

catch/finally内でawait 拡張メソッドでコレクション初期化子

例外フィルター

Page 8: Deep Dive C# 6.0

プロパティやメソッドの改善

•プロパティやメソッドがだいぶ書きやすく• 式形式の関数メンバー(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)

Page 9: Deep Dive C# 6.0

背景:よくあるコード(1)

•割と単純な計算

class Calculator{

public double Square(double x) { return x * x; }}

Page 10: Deep Dive C# 6.0

背景:よくあるコード(2)

•子オブジェクトに丸投げ

class Sample1 : Sample{

Sample _inner;public override string X() { return _inner.X(); }

}

Page 11: Deep Dive C# 6.0

背景:よくあるコード(3)

• readonlyにするためだけにフィールド定義

class Immutable{

private readonly int _x;public int X { get { return _x; } }

public Immutable(int x) { _x = x; }}

Page 12: Deep Dive C# 6.0

背景:よくあるコード(4)

•初期化するためだけにフィールド定義

class Root{

private List<string> _items = new List<string>();public IList<string> Items { get { return _items; } }

}

Page 13: Deep Dive C# 6.0

背景:共通していえること

• { 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 ; } })が多すぎ

Page 14: Deep Dive C# 6.0

式形式のメソッド/演算子

• 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;

Page 15: Deep Dive C# 6.0

式形式のプロパティ/インデクサー

• getter-onlyな場合だけ、同様に =>を使って短縮可能• { get { return ; } }を消せる

public int X { get { return _x; } }

public int X => _x;

Page 16: Deep Dive C# 6.0

自動プロパティ初期化子

•自動プロパティに対して初期化子が書けるように• 明示的なフィールド定義が不要に

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>();}

Page 17: Deep Dive C# 6.0

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; }

}

Page 18: Deep Dive C# 6.0

没案: プライマリコンストラクター

•当初予定では、もう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; }

}

プライマリコンストラクター(没)未

Page 19: Deep Dive C# 6.0

効能

•どのくらいのインパクトがあるか実測• 計測用のプログラム:

• https://github.com/ufcpp/UfcppSample/tree/master/Scribble/FindSingleStatementBody

• せっかくなのでMicrosoft.CodeAnalysisライブラリを利用

• 今仕事で使っているソリューションを1個、集計してみた

Page 20: Deep Dive C# 6.0

効能:メソッド統計

全体, 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%が => 化の恩恵を受ける

Page 21: Deep Dive C# 6.0

効能:プロパティ統計

全体, 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%が => 化の恩恵を受ける

Page 22: Deep Dive C# 6.0

効能:プロパティ統計

全体, 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。実際には書き替えしてない

Page 23: Deep Dive C# 6.0

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が呼ばれる

Page 24: Deep Dive C# 6.0

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.を付けたくない

Page 25: Deep Dive C# 6.0

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クラスの静的メソッドでインスタンス生成

Page 26: Deep Dive C# 6.0

元々はC#スクリプト用

• Roslynの最終目標には「C#スクリプト」も入っている• (手が回っていなくて未実装)

• 自作アプリに組み込んでマクロ実行

• REPL上で1行1行C#ステートメントを実行

•スクリプト実行時限定のつもりで機能を追加した

•あまりにも要望多すぎて、通常のC#にも実装

Page 27: Deep Dive C# 6.0

静的プロパティ/非静的クラス

•静的プロパティ可

•静的クラスである必要ない

using static System.DateTime;using static System.Console;

public class Program{

public static void Main(){

WriteLine(Now);}

}

普通の(static が付かない)クラス

(こっちは静的クラス)

静的プロパティ

Page 28: Deep Dive C# 6.0

拡張メソッド

•拡張メソッドは、静的メソッドとしては呼べない• 拡張メソッドとしては使える

LINQでおなじみのEnumerableクラス

Enumerable中の拡張メソッド

拡張メソッドを静的メソッドとしては呼べない

Page 29: Deep Dive C# 6.0

staticが付く理由

•もし、staticを付けないと• 当初提案では付けなくてもよかった

• 結構極悪なコードを書けてやばかったから修正

using System.Linq;

namespace System{

public static class Linq{

public static string nameof(Action x) => "";}

}

既存の名前空間と同名のクラス

元とは別の定義を紛れ込ませられる

Page 30: Deep Dive C# 6.0

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;あるいは

Page 31: Deep Dive C# 6.0

インデクサー/多段チェック

• ?[]でインデクサーに対しても nullチェック可能

• 1つの式で多段チェック可能

var m = team.Units?[0]?.Master;

var unit = team.Units != null ?team.Units[0] :null;

var m = unit != null ?unit.Master :null;

Page 32: Deep Dive C# 6.0

デリゲート/イベント呼び出し

• ?()とは書けない• 条件演算子 ? :との区別が構文上難しい

•デリゲートなら、?.Invokeで代用可能

void OnPropertyChanged(string propertyName)=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

Page 33: Deep Dive C# 6.0

用途

• null許容な文脈と、非null許容な文脈ははっきり分かれる

•許容する方で活躍するはず

一覧画面

A B

(順序・位置などに意味があるような)一覧画面では「空欄」があり得る

空欄をnullで表したり

C

詳細画面

Cweight : 327dimension: 14.6×14×3.5

詳細画面では無効な項目の表示は想定しない

タップで画面遷移

null許容(nullable) 非null (non-nullable)

Page 34: Deep Dive C# 6.0

没案: null非許容

•より重要なのは非nullの方• 現状のC#ではnullを認めないコードを書くのが大変

• C# 7.0で検討中

void ShowDetail(Unit! unit){

...}

(現状の案)!で非nullを明示

※ 既存のC#コードを壊さないように非null対応するのはかなり大変で妥協が必要• 古いコードが混在すると100%の非null保証は無理

• !を付ける必要あり

Page 35: Deep Dive C# 6.0

文字列挿入(string interpolation)

•文字列整形がだいぶ楽に• $から文字列を始める

• {}の中に任意の式が書ける

string.Format("({0}, {1})", x, y);string.Format("数値: {0:n}, 通貨: {0:c}", x);

$"({x}, {y})"$"数値: {x:n}, 通貨: {x:c}"

書式設定も使える

Page 36: Deep Dive C# 6.0

複数行

• $@から始める

• ちなみに逆(@$)はダメ(コンパイルエラー)

Console.WriteLine($@"x: {x}y: {y}");

Page 37: Deep Dive C# 6.0

string.Format化

•コンパイル結果

• 要望多かったのに今まで入れなかった理由は単純に「ライブラリでできることはライブラリでやれ」

• まさに「just-do-it」の代表格• Roslynになって保守コストが下がったから入れれた

string.Format("({0}, {1})", x, y);

$"({x}, {y})"

まんま、string.Formatが生成されるだけ

Page 38: Deep Dive C# 6.0

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型のインスタンスが作られる

カルチャー指定して文字列化

Page 39: Deep Dive C# 6.0

nameof式(nameof expression)

•識別子(変数名、メンバー名、クラス名…)を文字列リテラル化

if (x < 0)throw new ArgumentException("x must be positive");

if (x < 0)throw new ArgumentException(nameof(x) + " must be positive");

リファクタリングの対象にならない

リファクタリングの対象になる• 「リネーム」できる• 「定義に移動」できる• 「参照の検索」できる

Page 40: Deep Dive C# 6.0

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);

AddHoursCountRegex

Page 41: Deep Dive C# 6.0

補足: 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"の名前が渡る

Page 42: Deep Dive C# 6.0

補足: CallerMemberNameでは不十分

•パフォーマンス考えるとよりよい書き方があって

public int X{

get { return _x; }set { _x = value; PropertyChanged?.Invoke(this, XProperty); }

}private static readonly PropertyChangedEventArgs XProperty

= new PropertyChangedEventArgs(nameof(X));

同じインスタンスを使いまわす方がメモリ効率がいい

この場合、CallerMemberNameでは役に立たない

Page 43: Deep Dive C# 6.0

補足: 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では役に立たない

Page 44: Deep Dive C# 6.0

インデックス初期化子

•オブジェクト初期化子内にインデクサーを書ける

•利点• オブジェクト初期化子で、プロパティと混ぜれる

• 式になる• =>で使える、フィールド初期化子で使える、式ツリー化できる

var d = new Dictionary<string, int>{

["X"] = 1,["Y"] = 2,

};

Page 45: Deep Dive C# 6.0

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));

}}

プロパティ名がキーの辞書

Page 46: Deep Dive C# 6.0

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,

};

一瞬、こういう文法が提案されてた(キモいって言うやつ多すぎるからやめた)

Page 47: Deep Dive C# 6.0

Working with data

• C# 7.0の大きなテーマの1つ

• light weight dynamicはそのはしり

• 7.0にご期待ください• レコード型、タプル型

「データ」が主役

var d = new Dictionary{

["X"] = 1,["Y"] = 2,

};

低コスト、低リスクなこいつだけが6.0に残った

Page 48: Deep Dive C# 6.0

例外フィルター

•例外 catchに条件を付けれるように

•ちなみに• C#的には新機能だけど、.NET的には1.0のころから持ってる機能

• C#がそれに対応しただけ

try{

…}catch (Exception ex) when (ex.InnerException is IOException){

…}

Page 49: Deep Dive C# 6.0

用途: 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できない

Page 50: Deep Dive C# 6.0

用途: inner exceptionでcatch

static void Main(){

try{

RunAsync().Wait();}catch (AggregateException ae)

when (ae.InnerExceptions.Any(e => e is InvalidOperationException)){

Console.WriteLine("ここを通ってほしい");

}}

Page 51: Deep Dive C# 6.0

用途:複数種の例外

•複数種類の例外に対して同じ処理

try{

…}catch (Exception ex)

when (ex is AccessViolationException || ex is FileNotFoundException){

…}

Page 52: Deep Dive C# 6.0

没案: if

•当初提案ではifキーワードだった

• {}のちょっとした位置で意味が全く変わるとかちょっと

try{}catch (Exception ex) if (ex.InnerException is IOException) { … }

try{}catch (Exception ex) { if (ex.InnerException is IOException) … }

Page 53: Deep Dive C# 6.0

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

Page 54: Deep Dive C# 6.0

今までなかったのは

• yield return• awaitの発想の元になっているのがyield return

(awaitのコード生成結果はyield returnに近い)

• yield returnはtry-catch-finally句内に書けない

•生成されるコードが結構複雑• 一度すべての例外をcatch→await→再throw的なコードに展開される

• catch前のスタックトレースを保ったまま再throwする

Page 55: Deep Dive C# 6.0

拡張メソッドでコレクション初期化子

•コレクション初期化子の結果として呼ばれる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));

}

Page 56: Deep Dive C# 6.0

今までなかったのは

•コンパイル時間を気にしてのことらしい• 拡張メソッドの検索はノーコストではない

• といっても、普通の拡張メソッドとそんなにコスト変わらないはず

• VBは昔からできてた

Page 57: Deep Dive C# 6.0

まとめ

• Just-do-it• Roslyn化に時間をかけすぎたのでコンパクトに

• Roslynになったからこそ保守コストが下がって新機能入れやすく

• ローコスト・ローリターンな機能ばかりだけど、確実に便利に

•いくつかは、7.0の大きなテーマにつながる機能• データ:

• null: null条件演算子

インデックス初期化子拡張メソッドでコレクション初期化子

Page 58: Deep Dive C# 6.0

おまけ

•ここから先、時間が残れば

Page 59: Deep Dive C# 6.0

その他小さな変更

•これまでも、大々的に出てない小さな変更はあった• 特に、破壊的変更

• Visual C# 2008 Breaking Changes

• Visual C# 2010 Breaking Changes

• Visual C# Breaking Changes in Visual Studio 2012

• だいたいは以下の類• 新機能の余波でオーバーロード解決順序変わりました

• バグだったのでなおしました

• Roslynオープンソース化で、こういう小さな変更も見えやすくなった

Page 60: Deep Dive C# 6.0

C# 6.0の破壊的変更(1)

•コンストラクターの再帰循環参照• 昔:実行時にスタックオーバーフロー

• C# 6.0:コンパイルエラー

class C{

public C(int x) : this() { }public C() : this(0) { }

}

Page 61: Deep Dive C# 6.0

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}

Page 62: Deep Dive C# 6.0

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;}

Page 63: Deep Dive C# 6.0

日本人だけが気づく破壊的変更

• Unicodeの変更の影響• 昔:カタカナ中点(中黒)OK

• C# 6.0: Unicode側のミスでした。Unicodeが修正したらC#にも影響出ました

int x・y = 10;Console.WriteLine(x・y);

Page 64: Deep Dive C# 6.0

微妙な新機能(1)

• enumの基底型• 昔: int, short, longなど、キーワードでないとダメ

• C# 6.0: Int32, Int16, Int64など、System名前空間の型でもOK

enum X : System.Int32{

A, B, C,}

Page 65: Deep Dive C# 6.0

微妙な新機能(2)

•オーバーロード解決ルールを改善• 昔: ラムダ式の型推論、1段は行けてたけど2段は無理だった

• C# 6.0: 2段以上もOKusing 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?か古いコンパイラーは判定できない

Page 66: Deep Dive C# 6.0

追悼

•一瞬、C# 6.0に入る予定だったもの• 互換性壊れるので取りやめたり

• 引数なしの構造体コンストラクター

• C# 7.0で改めて取り組むことになったり• プライマリコンストラクター→ レコード型

• 変数宣言式→ パターンマッチング

Page 67: Deep Dive C# 6.0

追悼:構造体の引数なしコンストラクター•構造体にも引数なしのコンストラクターを定義できるようにするはずだった

• .NETのランタイムレベルでバグがあることが発覚して断念• Activator.CreateInstance<T>()が new T()をnullに置き換える

struct MyInt{

public readonly int Value;

public MyInt() { Value = -1; }public MyInt(int value) { Value = value; }

}

Page 68: Deep Dive C# 6.0

追悼:プライマリコンストラクター

•型定義の型名の直後にコンストラクターを1個書けた

• 7.0でレコード型に吸収予定

class Immutable(int x){

public int X { get; } = x;}

class Immutable(int x) { } 未

Page 69: Deep Dive C# 6.0

追悼:変数宣言式(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) { … }