clock-up-blog

go-mi-tech

型がふわっとした C# の dynamic 型。と宗教。

C# Advent Calendar 2018 - Qiita 2日目の記事です。

C# だと「常に厳密に型定義するんでしょ?めんどくさくない?」って言われることがありますが、別にそんなことないです。厳格な C#er からすると邪道呼ばわりされるかもしれませんが、C# には dynamic 型という柔軟な型があります。

今回は特に LL (Lightweight Language) 出身の方々が感じるであろう C# の硬いイメージをちょっと緩和させる意味でこの記事を書いてみます。

C# の dynamic 型をざっくり紹介

以下にコード見せます。はい。こんな感じに型がふわっとした変数は C# でも作れます。「var」のように型宣言を暗黙にしているのではなく、本当に実行時に型がふわっと決まる、そういう仕組み。

using System;
using System.Dynamic;

namespace EasyCsharpDynamic
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic a = 10;
            dynamic b = 20;
            dynamic c = 30; // 数値かと思いきや
            c = "hello"; // 実行時に途中から文字列に変えちゃってる.
            dynamic d = new ExpandoObject();
            d.hoge = 99;
            d.fuga = "world";
            dynamic e = a + b + c + d.hoge + d.fuga;
            Console.WriteLine(e); // 結果: 30hello99world
        }
    }
}

js とかでもだいたい同じようなことできますね。C# においても意外とこういう柔軟な(悪くいうと自由過ぎて危うい)変数の使い方もできます。

dynamic のもっと実用的な例:REST APIJSON を解釈するときとか

だいたい最近だとほとんどの Web REST APIJSON 形式を返すわけですが、それを C# で解釈しようとするときには「わざわざ応答形式に合わせたクラスを定義するんでしょ?めんどくさくない?」って言われたりもしますけど、別に型定義しなくても dynamic があれば LL っぽい JSON 解釈の仕方は普通にできます。

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace EasyCsharpDynamic
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Run(async () =>
            {
                using (var client = new HttpClient())
                {
                    // 桜島の 2018-11-30 ~ 2018-12-01 までのアクティビティ.
                    var json = await client.GetStringAsync(
                        @"http://api.aitc.jp/jmardb-api/search?datetime=2018-11-30%2000:00:00&datetime=2018-12-01%2000:00:00&areaname=%E6%A1%9C%E5%B3%B6");

                    // 応答 JSON 文字列をパースして dynamic 型として解釈.
                    var obj = JsonConvert.DeserializeObject<dynamic>(json);
                    foreach (var data in obj.data)
                    {
                        var headline = data.headline[0];
                        Console.WriteLine(headline);
                    }
                }
            }).Wait();
        }
    }
}

はい難しくない。

今回は 気象庁防災情報 XML 検索 API を利用させてもらいました。

これは実際には以下のような JSON が返ってくるもので、今回はそれのパース結果を dynamic で受け止めています。

{
  "data": [
    {
      "datetime": "2013-01-02T03:41:01.000+0900",
      "headline": [
        "火  山:桜島\n日  時:2013年01月02日03時35分(011835UTC) 第1報\n現  象:爆発"
      ],
      "link": "http://api.aitc.jp/jmardb-api/reports/67f1f2fa-c9a9-4747-9c65-5f4aca4fefa2",
      "title": "噴火に関する火山観測報"
    },
    {
      "datetime": "2013-01-02T03:46:31.000+0900",
      "headline": [
        "火  山:桜島\n日  時:2013年01月02日03時35分(011835UTC) 第2報\n現  象:爆発"
      ],
      "link": "http://api.aitc.jp/jmardb-api/reports/3dd6e44c-a7b2-4a9b-97be-4d2e4476b46c",
      "title": "噴火に関する火山観測報"
    },
    ....


今回のサンプルプログラム実行結果はこんな感じになります。

現在、桜島は噴火警戒レベル3(入山規制)です。桜島で噴火が発生した場合には、30日09時から12時までは火口から東方向に降灰が予想されます。
現在、桜島は噴火警戒レベル3(入山規制)です。桜島で噴火が発生した場合には、30日09時から12時までは火口から東方向、30日21時から24時までは火口から東方向に降灰が予想されます。
現在、桜島は噴火警戒レベル3(入山規制)です。桜島で噴火が発生した場合には、30日09時から12時までは火口から東方向、30日21時から24時までは火口から東方向に降灰が予想されます。
現在、桜島は噴火警戒レベル3(入山規制)です。桜島で噴火が発生した場合には、30日21時から24時までは火口から東方向に降灰が予想されます。
現在、桜島は噴火警戒レベル3(入山規制)です。桜島で噴火が発生した場合には、30日21時から24時までは火口から東方向に降灰が予想されます。
<火口周辺警報(噴火警戒レベル3、入山規制)が継続>
....(略)....

サンプル置き場

今回のサンプルコードは GitHub にも置きました。
github.com

総括

C# でも LL っぽいことは割とできます。LL の方々はそこまで C# を怖がらなくて良い。

C# がまだまだそれほど使われていない理由

僕は人に言語を勧めるときには一にも二にも C# を選ぶんですけれども、だいたい以下の理由で却下されたりします。

変数宣言と型付けめんどくさい?

変数宣言はともかくとして型付けは最初のうちは dynamic でぜんぜんイケます。まぁ C# 触っているうちに型付けの利点を正しく理解していけば dynamic どんどん不要になっていくんですけど。ただ、プロトタイプ作り時には dynamic は便利。

Windows が好きでない?

さすがにそろそろビルゲイツWindows をディスすことを何かしらのアイデンティティとするのはやめてほしいにゃあ。いや僕から見ても Windows のダメなところはたくさんあるんですけど。同様に他の OS にも同じくらいダメなところがある。これはたぶん慣れとお気持ちの問題でしかない。

今や MicrosoftGitHub に公式リポジトリを出す時代です。すんごい重宝。
github.com

ついでにいうと mono 使えば .NET Framework ベースの C#Linux とかで動かすこともできるし、最近だと .NET Core が正式に存在しているので、それをベースに C# 組むのであれば、それもまた Linux とかで動かすこともできます。

Visual Studio 高い?

まぁ、まずは趣味で触るだけだったら無償版でほとんど Pro と同程度の機能使えるので、まぁ。
visualstudio.microsoft.com

これが仕事にも使えると判断したら商用版を会社に買って貰いましょう。

さいごに:ここまで言っておいてなんだが、そもそも C# 利用者はぜんぜん少なくない

実は C# が「まだまだそれほど使われていない」と書いちゃいましたが、それは一部の方から見た印象を代弁したに過ぎなくて、実際のところは様々な場所でかなり使われてます。日本の場合だとエンタープライズが多いのでネットの個人記事とかに出てきにくいだけ。

ここ最近では Unity (や Xamarin()) が流行ってくれたおかげで C# 人口が増えたインパクトもけっこう大きい。家庭用ゲーム機のゲームですら割と C# 使われてる。
ちなみにかの有名な Stack Overflow もまた ASP.NET with C# で構成されています。C# 良いですよ。C# は良い。

nickcraver.com