tag:crieit.net,2005:https://crieit.net/tags/%E3%83%AF%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%8A%E3%83%BC/feed 「ワンライナー」の記事 - Crieit Crieitでタグ「ワンライナー」に投稿された最近の記事 2021-01-08T21:12:03+09:00 https://crieit.net/tags/%E3%83%AF%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%8A%E3%83%BC/feed tag:crieit.net,2005:PublicArticle/16567 2021-01-08T21:12:03+09:00 2021-01-08T21:12:03+09:00 https://crieit.net/posts/csharp-expression-bodied 【C#】ワンライナーで書ける式形式メンバー <h1 id="式形式メンバー"><a href="#%E5%BC%8F%E5%BD%A2%E5%BC%8F%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC">式形式メンバー</a></h1> <p>まずは下記のコードをご覧ください。</p> <pre><code class="csharp">public static bool IsNullOrEmpty(this string text) { return string.IsNullOrEmpty(text); } </code></pre> <p>上記は<a target="_blank" rel="nofollow noopener" href="/2020/12/30/csharp-extension-methods/">【C#】拡張メソッド</a>という記事で例示した、<code>string.IsNullOrEmpty()</code>を扱いやすくした拡張メソッドです。</p> <pre><code class="csharp">var text = ""; // これが Cnosole.Write(string.IsNullOrEmpty(text)); // こう書ける Console.Write(text.IsNullOrEmpty()); </code></pre> <p>という方法を実現する拡張メソッドですね。</p> <p>このコード、<code>string.IsNullOrEmpty()</code>を<code>return</code>しているだけなのに<code>{}</code>で括ってあげるのがなんか嫌じゃないですか?</p> <p>だって、<code>foreach</code>も<code>if</code>も、続く処理が単文(単一ステートメント)であれば<code>{}</code>は不要ですよね。</p> <pre><code class="csharp">// これは foreach (var n in Enumerable.Range(1, 20)) { Console.Write(n); } // こう書ける foreach (var n in Enumerable.Range(1, 20)) Console.Write(n); // これは if ((n == 3) || ($"{n}".Contains(3))) { Console.Write("アホ"); } // こう書ける if ((n == 3) || ($"{n}".Contains(3))) Console.Write("アホ"); </code></pre> <p>組み合わせて</p> <pre><code class="csharp">// これを foreach (var n in Enumerable.Range(1, 20)) { if ((n == 3) || ($"{n}".Contains(3))) { Console.Write("アホ"); } } // こう書ける foreach (var n in Enumerable.Range(1, 20)) if ((n == 3) || ($"{n}".Contains(3))) Console.Write("アホ"); </code></pre> <p>こうも書ける訳です。余計な<code>{}</code>がなくてスッキリしていますよね。特に先人の残した<strong>ネスト地獄</strong>のコードを読んでいると、<code>{}</code>なんて見るのも嫌じゃないですか。</p> <p>だから、メソッドでも<code>{}</code>なしで書きたいですよね?ですよね?</p> <p>メソッドも、<code>{}</code>を省略して書けるケースがあります。</p> <pre><code class="csharp">// これは public static bool IsNullOrEmpty(this string text) { return string.IsNullOrEmpty(text); } // こう書ける public static bool IsNullOrEmpty(this string text) => string.IsNullOrEmpty(text); </code></pre> <p>どうでしょうか?<code>{}</code>が減っただけですが、かなりスッキリしましたよね。</p> <p>こういう記法ができる式形式メンバーは<a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-version-history">C#6.0で実装され、C#7.0で拡張されました。</a></p> <h1 id="条件"><a href="#%E6%9D%A1%E4%BB%B6">条件</a></h1> <p>式形式メンバーは、単一ステートメントで記載されているメソッドやプロパティに使用できます。</p> <p>なので、たとえば以下のようなメソッドは、式形式メンバーは使用できません。</p> <pre><code class="csharp">// アホ毛・パーカー・ショートヘア・ニーソのいずれか2つ以上を満たせばボーイッシュとする public static bool IsBoyish(this GirlModel girl) { var boyishibility = 0; // アホ毛か if (girl.HasAhoge) boyishibility++; // パーカーか if (girl.IsWearingHoodie) boyishibility++; // ショートヘアか if (girl.HasShortHair) boyishibility++; // ニーソか if (girl.IsWearingKneeSocks) boyishibility++; // 判定 return (boyishibility >= 2); } </code></pre> <p>ですが、たとえばボーイッシュがより広く浸透した世界で、アホ毛・パーカー・ショートヘア・ニーソのいずれか一つでも満たせばボーイッシュといえるようになった場合は、下記のように書けます。</p> <pre><code class="csharp">public static bool IsBoyish(this GirlModel girl) => (girl.HasAhoge || girl.IsWearingHoodie || girl.HasShortHair || girl.IsWearingKneeSocks); </code></pre> <p>ちなみにアホ毛・パーカー・ショートヘア・ニーソは私のHN「あぱしょに」の<a target="_blank" rel="nofollow noopener" href="/2020/12/01/renamed/">名前の由来</a>です(小声)</p> <h1 id="書き方"><a href="#%E6%9B%B8%E3%81%8D%E6%96%B9">書き方</a></h1> <p>書き方は、<code>{}</code>の代わりに<code>=></code>を使用して、<code>return</code>を省略するという記法になります。</p> <pre><code class="csharp">// これは× // returnは書かない public static bool IsNullOrEmpty(this string text) => return string.IsNullOrEmpty(text); </code></pre> <p>この記法は、続くステートメントを<code>return</code>しますよ、ということをコンパイラに通知しているんですね。なので明示的に<code>return</code>は書けません。</p> <p><code>{}</code>を省略<strong>できる</strong>と書きましたがどちらかというと副産物的なメリットで、本来は<code>return</code>を省略するための記法ということになります。</p> <h1 id="戻り値を返さないメソッドにも使える"><a href="#%E6%88%BB%E3%82%8A%E5%80%A4%E3%82%92%E8%BF%94%E3%81%95%E3%81%AA%E3%81%84%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AB%E3%82%82%E4%BD%BF%E3%81%88%E3%82%8B">戻り値を返さないメソッドにも使える</a></h1> <p>戻り値を返さないメソッドに対しても、単一ステートメントのメソッドであれば式形式メンバーを使用できます。</p> <pre><code class="csharp">// これは public static void WriteToConsole(this object logMessage) { Console.Write(logMessage); } // こう書ける public static void WriteToConsole(this object logMessage) => Console.Write(logMessage); </code></pre> <p>これらのメソッドはもともと、ふつうは<code>return</code>を省略するかと思いますが式形式メンバーでも同様に<code>return</code>は書きません。</p> <h1 id="式形式メンバーは便利か"><a href="#%E5%BC%8F%E5%BD%A2%E5%BC%8F%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC%E3%81%AF%E4%BE%BF%E5%88%A9%E3%81%8B">式形式メンバーは便利か</a></h1> <p>個人的には、使えるところでは積極的に使っています。タイプ量が減るのも良いですが、ワンライナーで書けるのがやっぱり楽です。慣れてしまえば読む時でもメリットがあると思います。</p> <p>ただし、実際の処理が改行&インデントされていれば、それはそれで読みやすいということもあると思います。その辺りは個人の感覚によりけりですが、こういう記法があるということを知っているだけでも訳に立つと思います。</p> <h1 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-version-history">C# の歴史</a><br /> <a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members">式形式のメンバー (C# プログラミング ガイド)</a></p> あぱしょに