C# code refactoring with Scope Functions
by
Masaya Yashiro
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
スコープファンクションでコード の見通しを改善する 2018/09/26 Gotanda.unity #8 @yashims85
Slide 2
Slide 2 text
誰 ● Twitter: @yashims85 ● 会社: モバイルファクトリー@ 五反田 ● Unity: 趣味でさわってる ● 最近気になる言語: Rust ● 緩募: 継続するダイエット
Slide 3
Slide 3 text
質問です 皆さんはイケてないな。。。 と思いながら、そんなもんだろうと諦めて コードを書いていることはありませんか?
Slide 4
Slide 4 text
● PBXProjectのプロパティ ● 関数に外出しするほどではないちょっとし た計算 ● Builder, Factoryパターンを採用するほど でもないちょっとした手順 ● 大量のnullチェックもしくは ?. 地獄 私がイケてなぁと思いながらコードを書 いているとき
Slide 5
Slide 5 text
スコープファンクション もしかしたらスコープ ファンクションがそれ らの悩みを一助にな るかもしれません。
Slide 6
Slide 6 text
スコープファンクション ● Kotlinの文脈で登場する ● (基本的に)引数にLambdaを1つとって、そ の中で自己参照をする ● C#のExtensionで作った関数のように全部 のObjectに生えてる
Slide 7
Slide 7 text
なるほど
Slide 8
Slide 8 text
いくつか移植してみた CSharpScopeExtensions: https://github.com/yashims/CSharpScop eExtensions ここでスター欲しいって言えば 優しい人がしてくれるって聞きました
Slide 9
Slide 9 text
導入方法 ● releaseにunitypackageがおいてあるので ご自由にお使い下さい ● もしくは簡単なのでコピペ
Slide 10
Slide 10 text
実際の実装 今回は諸般の事情により2つだけ紹介
Slide 11
Slide 11 text
Also
Slide 12
Slide 12 text
Also public static T Also(this T self, Action action) { action(self); return self; }
Slide 13
Slide 13 text
Also public static T Also(this T self, Action action) { action(self); return self; } ジェネリクスのExtensionなので、どの Objectからも呼び出せる
Slide 14
Slide 14 text
Also public static T Also(this T self, Action action) { action(self); return self; } 自分自身を引数に取る Actionに自分 自身を渡す
Slide 15
Slide 15 text
Also public static T Also(this T self, Action action) { action(self); return self; } 戻り値として自分を返す。
Slide 16
Slide 16 text
Let
Slide 17
Slide 17 text
Let public static R Let(this T self, Func action) { return action(self); }
Slide 18
Slide 18 text
Let public static R Let(this T self, Func action) { return action(self); } ジェネリクスのExtensionなので、どの Objectからも呼び出せる
Slide 19
Slide 19 text
Let public static R Let(this T self, Func action) { return action(self); } 自分自身をFuncに渡し、Funcの戻り 値がLetの戻り値となる。
Slide 20
Slide 20 text
それがどしたの
Slide 21
Slide 21 text
実際の使用感をみてみる
Slide 22
Slide 22 text
Alsoの使い所 例えばインスタンスのプロパティ設 定
Slide 23
Slide 23 text
Alsoを使わない void Start() { Transform t1 = GetComponent(); Quaternion q1 = new Quaternion(); q1.x = 0; q1.y = 0; q1.x = 0; t1.rotation = q1; }
Slide 24
Slide 24 text
Alsoを使う void Start() { Transform t2 = GetComponent().Also((it) => { it.rotation = new Quaternion().Also((that) => { that.x = 0; that.y = 0; that.z = 0; }); }); }
Slide 25
Slide 25 text
Alsoを使う ● Start()のスコープを一時変数で汚さない ● いくつかの処理が記述されてるようならコレはメリット ● 引数の変数名を`it`等の代名詞にしておけば、何に対して の処理かが明確になり、それ以外に言及するコードを避 けられる ● コレを使えばPBXProjectの設定が超絶スッキリする
Slide 26
Slide 26 text
Letの使い所 例えばLINQのSelectの様に使う
Slide 27
Slide 27 text
Letを使わない Transform t = GetComponent(); float distanceX = t.parent.transform.localPosition.x + t.localPosition.x;
Slide 28
Slide 28 text
Letを使う float distanceX = GetComponent().Let((it) => { return it.parent.transform.localPosition.x + it.localPosition.x; });
Slide 29
Slide 29 text
Letを使う ● LINQやRxのSelectと同じイメージで、Lambda内で変形を 行える ● Alsoと同じく、一時変数でスコープを汚さない
Slide 30
Slide 30 text
Letの使い所 例えばC#6.xのnullableの unwrapping
Slide 31
Slide 31 text
Letを使わない string say(string comment) { return comment != null ? $"I said: {comment}" : ""; }
Slide 32
Slide 32 text
Letを使う string say(string comment) { return comment?.Let(it => $"I said: {it}") ?? ""; }
Slide 33
Slide 33 text
Letを使う ● C#でのnull条件演算子「?.」は、nullチェックして、非null であればローカル変数に格納するのと同義 ● それをLetの引数で受け取っているので、Letの中では Null安全な変数を自由に使える
Slide 34
Slide 34 text
できなかったこと
Slide 35
Slide 35 text
できなかったこと ● Lambdaの中でthisコンテキストを変える ● KotlinではLambdaの中ではthisがそれ自身になるス コープファンクションがある(例: Apply)
Slide 36
Slide 36 text
Apply(実現できたら) public static T Apply(this T self, Action action) { self.action(); return self; }
Slide 37
Slide 37 text
Apply(実現できたら) public static T Apply(this T self, Action action) { self.action(); return self; } ジェネリクスのExtensionなので、どの Objectからも呼び出せる
Slide 38
Slide 38 text
Apply(実現できたら) public static T Apply(this T self, Action action) { self.action(); return self; } TをthisとしてActionを呼び出す
Slide 39
Slide 39 text
Apply(実現できたら) public static T Apply(this T self, Action action) { self.action(); return self; } 自分自身を返す
Slide 40
Slide 40 text
Applyを使えたら void Start() { Transform t2 = GetComponent().Apply(() => { this.rotation = new Quaternion().Apply(() => { x = 0; y = 0; z = 0; }); }); } this以外の事について言及する余地 が無くなる
Slide 41
Slide 41 text
まとめ
Slide 42
Slide 42 text
まとめ ● ScopeFunctionを使うと一時変数が減ら せ、コードの見通しが良くなる ● ブロックで区切られることで、何について述 べられているコードかが簡潔になる ● Lambdaの中でthisを変える方法があった ら誰か教えてください
Slide 43
Slide 43 text
ありがとうございました