Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Unityで使える C# 6.0~と .NET 4.6

18.464 Aufrufe

Veröffentlicht am

http://peatix.com/event/311392 にて登壇。

Unity 2017 で、C# 6.0が使えるようになりました。また、Experimental とはいえ、 .NET Framework 4.6 相当の機能が使えるようになりました。
本セッションでは、これまで Unity の制限から C# 3.0(一部4.0)/.NET 3.5しか使ったことのない方々向けに、C# 6.0/.NET 4.6までの差分の中からいくつかお勧めの機能を紹介します。
また、これまでUnity 5.5/.NET 3.5向けに作っていたゲームを、Unity 2017/.NET 4.6に移行した作業について話します。

Veröffentlicht in: Technologie
  • Dating for everyone is here: ♥♥♥ http://bit.ly/36cXjBY ♥♥♥
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • Sex in your area is here: ❶❶❶ http://bit.ly/36cXjBY ❶❶❶
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier

Unityで使える C# 6.0~と .NET 4.6

  1. 1. Unityで使える C# 6.0~と .NET 4.6 岩永 信之
  2. 2. はじめに • 普通に使う分にはnet46/C#6.0使っとけばいいと思う • しんどいのは 1. Unityの外でビルドしたDLLの利用 • 特に、NuGet.org からのパッケージ参照 • net35とnet46の混在(社内にUnity5系プロジェクトが残ってる) 2. 互換ライブラリの移植 • net4以降のライブラリをnet35向けに移植して使ってた • 移植漏れで本家と微妙に挙動が違う
  3. 3. 今日話すこと • net46化、C# 6.0 (以降)化のメリットをちょこっと • 「しんどいの」の話とその対処
  4. 4. C# 6.0/.NET 4.6
  5. 5. 8年分のアップデート 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 C# 3.0/.NET 3.5 C# 6.0/.NET 4.6 約8年 LINQ C# 4.0 C# 5.0 C# 7.0 C# 7.1 C# 7.2 dynamic async/await 細々とたくさん (Roslyn) タプル パターン マッチ ref + 構造体C# 3~6の間の変化としては これが一番大きい パフォーマンス改善 ゲーム開発的にはこ れの方が欲しいかも
  6. 6. ということでasync/await • 非同期処理を同期っぽく書ける • ちゃんとコールバック呼び出しに変換される • スレッドをブロックしない var c = new HttpClient(); var res = await c.GetAsync("http://ufcpp.net"); var content = await res.Content.ReadAsStringAsync(); 例 awaitって書くだけで 非同期処理を 同期っぽく待てる この間、UIスレッドを止めない ゲームがフリーズしない • ゲームではフリーズしないの大事 • スマホゲーなんて通信だらけ • await大事
  7. 7. Taskクラス • async/awaitのお供にTaskクラス • (System.ThreadingTasks名前空間) • ちなみに • 所定のパターンを満たせばTask以外でもawait可能 • でも、たいていの場面ではTaskでOK var c = new HttpClient(); var res = await c.GetAsync("http://ufcpp.net"); var content = await res.Content.ReadAsStringAsync(); Task<HttpResponseMessage> GetAsync(string requestUri);
  8. 8. Taskとコルーチン • Q. コルーチンではダメ? • UnityEngine.dllの参照要らない(Unityの外とのコード共有) • 非同期I/O向けにはTaskの方が効率いい • コルーチンは本来「毎フレーム1回Updateが呼ばれるような処理」向け • 戻り値の受け渡しがだいぶ楽 var c = new HttpClient(); var res = await c.GetAsync("http://ufcpp.net"); var content = await res.Content.ReadAsStringAsync(); 戻り値! さっきの例
  9. 9. TaskとJob System • Unity、今度Job Systemとかいうの入れるって言ってるけど? • (自称)速いらしいけど… • 用途が絞られてる上に、結構特殊処理っぽい • Parallel†代わりにはなってもTask代わりにはならない 並 列 計 算 非 同 期 I / O † System.Threading.Tasks名前空間の静的クラス。 並列Forとか並列ForEachメソッドを持ってる
  10. 10. TaskとRx • Q. Rxとの違いは? • Rxの債務は2つある • Taskと同じ、戻りを1個受け取るタイプの非同期処理 • イベント • 前者の用途ではUnity以外ではあんまり流行らなかった • Taskの方が受け入れられやすかった • Q. Taskに移行した方がいい? • A. No • UniRxのままでawaitできる • 所定のパターンを実装していれば何でもawaitできる • UniRxは当然実装してる† † https://github.com/neuecc/UniRx/blob/master/Assets/Plugins/UniRx/Scripts/Observable.Awaiter.cs
  11. 11. 弊社内の話: Task • .NET 3.5向けの移植ライブラリを作って使ってる • Unity 4系の頃からずっともうawait使ってる • 5年くらい運用 • Unityエディター内で使えないんで、外でビルド • DLL化してからUnity内にコピー • コピー用のPostBuildテンプレートを使ってる • Unityエディター内ではコルーチンとの相互変換を提供 • await使えないとか無理
  12. 12. await以外におすすめC#新機能は? • 4.0 … dynamicはスマホでは使いにくいので無視でOK • 6.0 … 小さくて便利な改善が多々 • できることが増えるわけじゃない • 既存機能の書き心地が良くなる類 • 1個1個紹介してたら切りがないぐぐれ • 「最新をキャッチアップしましょう」とか意識高いこと言う気ない そんなずぼらなあなたに朗報 Visual Studio 2015/2017が最新機能を教えてくれます!
  13. 13. Visual Studioが教えてくれます • こんなの • C# 6.0以降、「今のC#ならこう書けるよ」的な提案が出てきて 機械的にコード書き換えてくれる 一部紹介していきます(当然のようにVS 2017で) クイック アクション (電球マーク) • 古い書き方を新しい書き方 に自動で書き換えてくれる • 書き換えの前後を目視確認 できる
  14. 14. C# 6.0: 式形式メンバー int F(int x) { return x * x; } int F(int x) => x * x; 変更前 変更後 • return 1つだけのメソッドを =>形式に変更 • 可逆(戻すアクションあり)
  15. 15. C# 6.0: nameof演算子 void F(string str) { } void F(string str) { if (str == null) { throw new ArgumentNullException(nameof(str)); } } 変更前 変更後 • 引数のnullチェックを追加 • 引数名はnameof演算子で 取れる
  16. 16. C# 6.0: 文字列補間 string.Format("({0}, {1})", x, y) $"({x}, {y})" 変更前 変更後 • $から始まる文字列を書くと {}内に値を展開できる
  17. 17. C# 6.0: null条件演算子 obj != null ? obj.ToString() : null; if (a != null) a(); obj?.ToString(); a?.Invoke(); 変更前 変更後 • ?. 演算子でnullを伝搬 • [] もOK • () はダメなので ?.Invoke
  18. 18. C# 7.0: パターン(型スイッチ) var d = obj as IDisposable; if (d != null) { d.Dispose(); } if (obj is IDisposable d) { d.Dispose(); } 変更前 変更後 • as + nullチェックを is 1個で書ける
  19. 19. おまけ: コンストラクター生成 class Point { public int X { get; } public int Y { get; } } class Point { public int X { get; } public int Y { get; } public Point(int x, int y) { X = x; Y = y; } } 変更前 変更後 • プロパティからコンストラクター を作れる • 逆も可(コンストラクター引数か らプロパティ)
  20. 20. 弊社の話: 新機能への追従 • Task同様「Unityの外でビルド」で元からC# 7.1使ってる • Q. バージョン上がるたびに社内啓蒙とか必要? • A. awaitくらい大きな機能ならともかく、細かいものはNo • 新機能は使いたい人が使えばいいと思ってる • 自分は容赦なく使ってるけど、自分が使ってれば周りは割とついてくる • クイック アクションがあるものは、割とみんなすぐに使いだす • IDEは学習ツールでもある
  21. 21. その他、net46のメリット • NuGetパッケージの利用 • 最近さすがにnet35サポートを切ったライブラリが増えてる • Task(async/await)が真っ当に使えるのはnet45から • netstandard1.0 = net45 • Windows 8以降、net35は標準インストールされていない ↓ • net46なら使えるライブラリの幅が大きく増える
  22. 22. 移行で苦労した話
  23. 23. 始めに: C#の互換性 • 言語としては、C#はすごく互換性しっかりしてる • ソースコードレベルだと、大概大丈夫 • 学生時代に書いたC# 2.0コード、そのままで今もビルドできた • Unityで、C# 3.0 → 6.0 程度の変化はどうということない • ソースコードならね… • しんどくなる原因 • Unityの外と共有/外でDLL化 • Unity 5系が残ってるので、共通コードは.NET 3.5/4.6両対応 • NuGetパッケージをnuget.orgから取ってきて使おうとしてる
  24. 24. 苦労の理由1: Unityの外でDLL化 • メリット • C# 7.1も使える • Unityビルド時間短縮 • nuget.orgからライブラリを取ってこれる • デメリット • ビルドに1手間かかる • ビルド後、DLLをUnity配下にコピー • デバッグ実行のためにcsprojを書き換えたり mdb生成したり • Unityのバグをよく踏む… • やってる人が少ないせい 社内共通ライブラリの net46化に苦労したのも 大体この辺り 踏んだ問題をいくつか紹介
  25. 25. TargetFramework net46 • TargetFrameworkをnet46に変えないとうまく動かなかった • 補足: 本来、net46はnet35の上位互換のはずなのに… • たぶん、標準ライブラリのDLL整理をしたせい net35の頃 = monolithic net4以降 = fine-grained int, string, DateTime List<T>, HashSet<T> Thread File mscorlib int, string, DateTime List<T>, HashSet<T> Thread File System.Runtime System.Collections System.Threading System.IO
  26. 26. TargetFramework net46 • 対処 <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <LangVersion>latest</LangVersion> <TargetFramework>net35</TargetFramework> <DebugType Condition="'$(Configuration)'=='DEBUG'">full</DebugType> </PropertyGroup> </Project> 共通ライブラリのcsproj 元 補足: SDK-based csproj Skd属性を付けておくとcsprojが単純化できる (Visual Studio 2017以降の機能) SDK-basedにするとデバッグ情報の形式が変わる (Unityが未対応) しょうがないから古い形式で出力する設定追加
  27. 27. TargetFramework net46 • 対処 <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <LangVersion>latest</LangVersion> <TargetFrameworks>net35;net46</TargetFrameworks> <DebugType Condition="'$(Configuration)'=='DEBUG'">full</DebugType> </PropertyGroup> </Project> 共通ライブラリのcsproj 書き換え内容 ① TargetFrameworkタグを TargetFrameworks (複数形)に ② ; 区切りでnet46を追加† † Unity5系のプロジェクトも社内に残ってるのでnet35サポートは切れない
  28. 28. System.Runtime.dll等の参照 • 「アセンブリが見つからない」実行時エラー • NuGetでライブラリ参照したとき • Android/iOSビルドでだけ問題が起きたりする • 対処 • 同名のDLLをMonoBleedingEdgeフォルダーからコピーしてくる net4以降 = fine-grained int, string, DateTime List<T>, HashSet<T> Thread File System.Runtime System.Collections System.Threading System.IO この辺りのDLLが標準で コピーされない不具合† † バグ報告が出ているので、そのうち治ってくれるはず
  29. 29. 苦労の理由2: 自前の互換ライブラリ • 使ってた互換ライブラリ • net35時代にTask(async/await)を使うために • MinimumAsyncBridge • System.Threading.Tasksのnet35向けバックポート • 本家RxとUniRx混在 • UniRxをフォークして手を入れてる • net46になったし • 互換ライブラリを捨てたい • 本家に以降 移植漏れで本家と微妙に挙動が違う • 主に、マルチスレッド絡み (UIスレッドに戻るタイミングが違う等)
  30. 30. 苦労の理由2: 自前の互換ライブラリ • 移植漏れで本家と微妙に挙動が違う • 対処 • トライ&エラーしかなかった… • 例 • UIスレッド絡みの挙動は実行時エラーを起こす → 実行時エラーを見つけては、UIスレッドに戻す処理を手で追加 • 内部的にリフレクションを使っていて呼べないメソッドがある → 実行時エラーを見つけては、そのメソッドを別のオーバーロードに置き換え
  31. 31. おまけ: その他今踏んでるバグ C# 7.2が使いたくて困ってる話 Unity側に対応してもらう以外どうしようもなさげ
  32. 32. タプルが使いたい • C# 7.0からの機能 • ()で匿名の構造体を作れる構文 • 内部的にValueTuple構造体に依存 • Unityの問題 • 症状: Androidでだけ例外を起こす • 原因: Unityが.NET Standardなライブラリに対応していない • 状況: 2018.1で.NET Standardに対応するって言ってる var t = (1, 2); var (x, y) = t; var t = (1, 2); var t = new ValueTuple<int, int>(1, 2);
  33. 33. Visual Studio 15.5を使いたい • 最新のプレビュー版 • C# 7.2(プレビュー)が使える • ソリューションのロード時間が数倍早くなってる • 今、社内ライブラリで問題になっている不具合が修正されたっぽい • Unityの問題 • 症状: 特定のコードでUnity Editorが即死 • 原因: ポインターの扱いがsignedからunsignedに変わった • C#コンパイラーの挙動変更(パフォーマンス改善のため) • Unityが使ってるバージョンのMonoが命令変更に対応していないっぽい • 状況: 調査中とのこと string s; fixed(char* p = s) { }
  34. 34. Span<T>を使いたい • C# 7.2世代で同時に追加される予定の構造体 • パフォーマンス改善にかなり効く • 内部的にUnsafeクラス†を利用 • Unityの問題 • 症状: Androidでだけ例外を起こす • 原因: UnsafeクラスはC#じゃなくて、ILアセンブラーで書かれてる • Unityが使ってるバージョンのMonoが(C#では書けない)命令に対応していないっ ぽい • 状況: 調査中とのこと† https://www.nuget.org/packages/System.Runtime.CompilerServices.Unsafe/ void SafeMethod() { Span<byte> buffer = stackalloc byte[256]; } これまでunsafeコード必須だっ たような最適化を安全に書ける
  35. 35. まとめ
  36. 36. まとめ • Unityで閉じてる分にはnet46化もそんなに大変じゃない • C#は後方互換しっかりしてる • Unityの外でDLL作る/外からDLLを持ってくるとちょっと大変 • C# 7.1を使う • nuget.orgから取得 • 互換ライブラリの移植で多少苦労 • 本家との微妙な挙動差をトライ&エラーでちまちま修正 • Visual Studio 15.5/C# 7.2化でだいぶ困ってる • Unity側の対応待ち(自前では回避できなさそう)
  37. 37. http://www.cryuni.com/

×