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.

.NET Core 2.x 時代の C#

https://www.microsoft.com/ja-jp/events/decode/2018/
de:code 2018
セッションID: AD19
日本の第一人者が語る! C# の現状と今後への展望 「.NET Core 2.x 時代の C#」

  • Login to see the comments

.NET Core 2.x 時代の C#

  1. 1. 日本の第一人者が語る! C# の現状と今後への展望 「.NET Core 2.x 時代の C#」 AD19
  2. 2. 今日のテーマ 去年のde:codeで話したこと
  3. 3. 今日のテーマ った すなわち、今年
  4. 4. その他、去年話したこと 既存機能 最近出たて 将来の話
  5. 5. .NET Core .NET Coreも「生みの苦しみ」の時期を抜けた
  6. 6. .NET Core
  7. 7. 昔: .NET Core 1.0の頃 .NET Framework .NET Core 移植済み Windows依存強 •レジストリー •Drawing •ODBC マイナー機能 移植しない •UWP XAML •WPF 新規実装
  8. 8. 今: .NET Core 2.0~2.1 Windows Compatibility Pack マイナー機能も大体移植 .NET Framework 移植しない •UWP XAML •WPF .NET Core 移植済み 新規実装 • 残ってるのはGUIくらい • GUIは今後もクロスプラット フォームにはならない(でか すぎて無理) • でも、こっちにしかない機能 がある限り、サポートは絶対
  9. 9. 今: .NET Core 2.0~2.1 Windows Compatibility Pack マイナー機能も大体移植 .NET Framework 移植しない •UWP XAML •WPF .NET Core 移植済み 新規実装 • 新機能はまず.NET Coreで実装 • 今のところ.NET Frameworkに「移植」作 業してる • 移植作業もしんどい • パフォーマンスはCoreだけが向上して たり • .NET Frameworkはside by sideじゃなくて
  10. 10. 今: .NET Core 2.0~2.1 Windows Compatibility Pack マイナー機能も大体移植 .NET Framework 移植しない •UWP XAML •WPF .NET Core 移植済み 新規実装 • Windows依存が強い機能も.NET Coreに移 植 • 一部はどのプラットフォームでも動く • 一部はWindows限定 • APIだけがある。呼び出すと実行時例外https://blogs.msdn.microsoft.com/dotnet/2017/11/16/announcing-the-windows-compatibility-pack-for-net-core/ • RuntimeInformation.IsOSPlatform でif分岐必要 • コンパイル時に呼び出し可能かどうかを調べるアナライ ザーあり
  11. 11. 将来: .NET Core 3.0 Windows Compatibility Pack GUIも.NET Core上に •UWP XAML •WPF .NET Core 新規実装 • あくまで.NET Core上にWindows限定機能 が載ってるだけ(クロスプラットフォームで は動かない) • GUIでも.NET Coreの恩恵を受けたい • パフォーマンス向上 • side by sideインストール ML.NET •機械学習
  12. 12. 将来: .NET Core 3.0
  13. 13. パフォーマンス
  14. 14. 標準ライブラリの実装改善(1) if ((uint)x < length) 元 後 if (0 <= x && x < length)
  15. 15. 標準ライブラリの実装改善(2) if (9割方true) 短い処理 else 長い処理をメソッド抽出 (); 元 後 if (9割方true) 短い処理 else 長い処理
  16. 16. JIT intrinsics (1) enum A { X = 1, Y = 2 } A a = A.X; a.HasFlag(A.Y); IL_0002: ldloc.0 IL_0003: box A IL_0008: ldc.i4.2 IL_0009: box A IL_000e: call HasFlag ボックス化が起きて重たいの で有名 ※ intrinsics: 「内在的な」って意味の単語。この場合「中に組み込まれてる処理」くらいの意味。
  17. 17. JIT intrinsics (2) interface I { void M(); } struct S : I { void I.M() { } } S s = default; ((I)s).M(); 明示的実装 その呼び出 し IL_0002: initobj S IL_0008: ldloc.0 IL_0009: box S IL_000e: callvirt M これもボックス化を 起こす
  18. 18. Hardware intrinsics if(X86.Sse.IsSupported) { var c = X86.Sse.Add(a, b); } if(Arm64.Simd.IsSupported) { var c = Arm64.Simd.Add(a, b); } 現在の環境でこの命令セットが使える かどうか x86 CPUのADDPS命令に 展開 ARM64のADD命令に展 開
  19. 19. Hardware intrinsics
  20. 20. ランタイムの修正が必須な機能 「需要があるのはわ かる」 「実装もそんなに難しく ない」 「でも、ランタイムに手を入れないといけないか ら無理」
  21. 21. ジェネリック属性 class SomeAttribute<T> : Attribute { } [Some<string>] class Target { }
  22. 22. インターフェイスのデフォルト メソッド interface I<T> { T this[int index] { get; } public T First() => this[0]; }
  23. 23. C#マイナー リリース 小さく、高頻度にリリース
  24. 24. C#の小数点リリース
  25. 25. スケジュール感 de:code VS 16.0 (未定/推定) C# 8.0 VS 15.8 (未定/推定) build
  26. 26. マイナー リリース
  27. 27. 小分けの例1: タプル var (x, y) = (1, 2); • 複数の値をひとまとめに • 多値戻り値とかに使える var (x, y) = (1, 2); var t = (x, y); WriteLine(t.Item1); 7.0時点では 「Item1」に
  28. 28. 小分けの例1: タプル var (x, y) = (1, 2); var t = (x, y); WriteLine(t.x); タプル要素名を決 定 タプルを作るときに渡したx, yから var (x, y) = (1, 2); WriteLine((x, y) == (1, 2)); • タプル同士を==で比較 • メンバーごとに==を&&で繋 いだのと同じ結果
  29. 29. 小分けの例2: ref ref int M(ref int x) { ref var r = ref x; return ref r; } 参照でもらったも のを ローカルで参照 して 戻り値で返 す unsafe struct Pointer { int* p; public ref int this[int i] => ref p[i]; } nativeコード、unsafeコードとのつなぎに便 利だったり
  30. 30. 小分けの例2: ref ref readonly int M(in int x) { ref readonly var r = ref x; // r = 1; みたいな書き換えができ ない return ref r; } • 書き換えはできない参照を作れ る • ref readonly • 引数の場合はin (out引数との対 比)
  31. 31. 小分けの例2: ref struct Vector { public double W; public double X; public double Y; public double Z; public static Vector operator +(in Vector p, in Vector q) => ...; } 合計64バイトあって コピーするにはちょっ と大きい • コピーを避けて使える • 不用意に書き換えられない保証 あり • 演算子にも使える
  32. 32. 小分けの例2: ref int x = 1, y = 2; ref var r = ref x; r = 10; // x が書き換わ る r = ref y; r = 20; // y が書き換わ る 「何を参照するか」自体を書 き換え
  33. 33. リリースが早くなって 楽に作れて需要の高いものだけ 先に
  34. 34. バグの例1: defaultリテラル(C# 7.1) Dictionary<string, string> table = default(Dictionary<string, string>); Dictionary<string, string> table = default;
  35. 35. バグの例1: defaultリテラル(C# 7.1) void M(int? x = default) { } int?の規定値はnullなので、当然、nullであ るべき • VS 15.3(リリース時点) : 0になってた • VS 15.4(修正版) : nullに
  36. 36. バグの例2: in引数(C# 7.2) // 2変数、既定値付き static void M(in int x = 0, in int y = 0) => WriteLine(y); // 1変数だけ値を渡す static void Main() => M(1); yには0が入ってほしい • VS 15.5(リリース時点) : なぜかnull参照 例外発生 • VS 15.6で修正
  37. 37. バグの例2: in引数(C# 7.2) class X { // クラスに対して in 引数 static void S(in X x) => WriteLine(x.ToString()); // in 引数相手に this を渡す void M() => S(this); } • VS 15.5(リリース時点) : ExecutionEngineException発生 • VS 15.6(修正版)で修正
  38. 38. リリースが早くなっているので
  39. 39. パフォーマンス パフォーマンスを上げるためのライブラリ・言語機 能
  40. 40. C#でパフォーマンス?
  41. 41. … 7B 0D 0A 20 20 22 69 64 22 3A 20 31 2C 0D 0A 20 20 22 6E 61 6D 65 22 3A 20 22 F0 9F 91 A6 F0 9F 8F BD 22 0D 0A 7D … 7B 0D 0A 20 20 22 69 64 22 3A 20 31 2C 0D 0A 20 20 22 6E 61 6D 65 22 3A 20 22 F0 9F 91 A6 F0 9F 8F BD 22 0D 0A 7D Stream.Read(byte[] buffer, int offset, int count) Encoding.GetString(byte[] bytes) … 22 00 69 00 64 00 22 00 3A 00 20 00 31 00 2C 00 0D 00 0A 00 20 00 20 00 22 00 6E 00 61 00 6D 00 65 00 22 00 3A 00 20 00 … string.Substring string.Substring 31 00 1 22 00 3D D8 66 DC 3C D8 FD DF 22 00 "👦🏽" UTF-8 UTF-16
  42. 42. … 7B 0D 0A 20 20 22 69 64 22 3A 20 31 2C 0D 0A 20 20 22 6E 61 6D 65 22 3A 20 22 F0 9F 91 A6 F0 9F 8F BD 22 0D 0A 7D … Utf8String Utf8String Utf8String 1 "👦🏽" 直接intにParse すればヒープ不 要 ToString時に 初めてヒープ確 保 Substring
  43. 43. この辺りがま だ ちょっと道半 ば
  44. 44. C# 7.0 struct A { int[] array; ref int First => ref array[0]; } unsafe struct B { int* pointer; ref int First => ref pointer[0]; } 戻り値を参照にで きる unsafeなものも返 せる ref int M(ref int x) => ref x; ref int N() { int x = 0; return ref x; } 外からもらったものは返 せる 中のものは返せ ない
  45. 45. C# 7.2 Span<int> M(Span<int> x) => x; Span<int> N() { Span<int> x = stackallock int[4]; return x; } 外からもらったものは返 せる 中のものは返せ ない Span<T>で受け取るなら、 unsafeなしでstackallockが使え る
  46. 46. C# 7.3 Span<int> x = stackallock int[] { 1, 2, 3 }; Span<int> y = stackallock[] { 1, 2, 3 }; Span<int> x = stackallock[] { 1, 2, 3 }; unsafe { fixed (int* p = x) { } }
  47. 47. System.IO.Pipelines Span<T>を前提にしたI/O int Read(byte[] buffer, int offset, int count) int Read(Span<int> buffer)
  48. 48. https://blogs.msdn.microsoft.com/dotnet/2018/04/18/performance-improvements-in-net-core-2-1/ Span<T>による最適化
  49. 49. UTF-8を前提にした文字列処理
  50. 50. C# その他の機能 C# 7.3: ここまでのテーマにもれた機能もいくつか紹 介 C# 8.0: 少し先の話も
  51. 51. C# 7.3: オーバーロード解決の改善 static void M<T>(this T x) where T : class { } static void M<T>(this ref T x) where T : struct { } static void X(string s, int i) { s.M(); i.M(); } 前までは呼び分けできな かった 型制約違い
  52. 52. C# 7.3: ジェネリック型制約の追加 static void E<T>(this T x) where T : System.Enum { } static void D<T>(this T x) where T : System.Delegate { } static void U<T>(this T x) where T : unmanaged { } 列挙型だけを受け付 ける デリゲート型だけを受け 付ける ポインター化可能な型だけを受け 付ける
  53. 53. マイナー/メジャー並行開発 C# 7.0 C# 7.1 C# 7.2 C# 7.3 null許容参照型 再帰パターン range async stream インターフェイスのデフォルト実装 タプル改善 ref改善 タプル改善 ref改善 C# 8.0 タプル ref パターン
  54. 54. https://github.com/dotnet/csharplang/wiki/Nullable-Reference-Types-Preview https://github.com/dotnet/csharplang/wiki/vNext-Preview 8.0プレビュー、はじめました
  55. 55. C# 8.0: null許容参照型 int M(string s) { return s.Length; } int N(string? s) { var x = s.Length; if (s == null) return -1; return s.Length; } 単にこう書くと非 null 参照型でも、?でnull許容 に nullチェックがないので 警告 nullチェックより後なの でOK 既存コードを壊さないために • オプションでモード切替可能 に • null、非null、「未指定」 • 既存コードは「未指定」扱 いでコード解析する
  56. 56. C# 8.0: 再帰パターン int M(object obj) { switch (obj) { case int i: return i; case string s: return s.Length; case Point (var x, var y): return x * y; case Point { X : var x, Y : var y }: return X * Y; } throw new IndexOutOfRangeException(); } int M(object obj) => obj switch { case int i => i, case string s => s.Length, case Point (var x, var y) => x * y, case Point { X : var x, Y : var y } => X * Y, _ => throw new IndexOutOfRangeException() }; switch式
  57. 57. C# 8.0: Range var array = new[] { 1, 2, 3, 4, 5 }; var x = array[1..3]; // 1以上、3未満 var x = array[1..^1]; // 1~末尾から1 0 1 2 3 4 { 1, 2, 3, 4, 5 } 0 1 2 3 4 { 1, 2, 3, 4, 5 }
  58. 58. C# 8.0: async stream async IAsyncEnumerator<int> MAsync() { for (int i = 0; i < 5; i++) { await Task.Delay(1); yield return i; } } foreach await (var x in MAsync()) { }
  59. 59. まとめ
  60. 60. © 2018 Microsoft Corporation. All rights reserved. 本情報の内容(添付文書、リンク先などを含む)は、作成日時点でのものであり、予告なく変更される場合があります。

×