Visual Studio 2013 + Hyper-V で Xamarin.Android を動かそう

Visual Studio 2015 preview を使って Hyper-V で Xamarin.Android を動かそう | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6648

では、Visual Studio 2015 preview で Hyper-V の Android エミュレータを動かす方法を紹介しましたが、もう少し頑張ると現状の Visual Stuido 2013 からも Android エミュレータを動かすことができます。

注)動かせるのは動かせるのですが、Visual Studio からデバッグモードで動かすことはできなくて、何故か Release モードでデプロイした後に、エミュレータ上でアプリを起動できる、ってところまでです。デバッグ時に「Couldn’t connect to logcat, GetProcessId returned: 0」が出てデバッグ用のコネクションが接続しないのですが、アプリのデプロイは成功している状態になりました。

Visual Studio 2015 Preview をインストールする

Preview 版自体をインストールしない方法を模索してはいるのですが、ちょっと無理そう。ただし、Preview 版であっても 2013 と同居ができるので、この方法を使います(たぶん、2010 や 2012 が入っている状態でも同じだと思います)。

Visual Studio 2015 Downloads
http://www.visualstudio.com/downloads/visual-studio-2015-downloads-vs

  1. 実機 PC に Visual Studio 2015 preview をインストールする。
  2. 実機 PC の Hyper-V を有効にする。
  3. 最初の Xamarin Android プロジェクトを作って、リンク先から XamarinInstaller-VS2015 をダウンロード&インストールする。
  4. Visual Studio 2013 の拡張機能を 2015 へコピーする
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Xamarin\ を
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common\IDE\Extensions\ にコピーする。インストーラが Visual Studio 2013 のほうにしか拡張機能をコピーしないためです)
  5. C:\Program Files (x86)\NuGet\Visual Studio 2015\NuGet.Tools.vsix を実行して拡張機能を有効にする。
  6. Bussiness アカウントでログインをして、Xamarin Update で Statble に戻す。
  7. Statable に戻すときに、何故か元に戻しすぎてログインができない状態までになるが、慌てずに xamarin.com から XamarinInstaller をダウンロードして、再インストールすれば回復します。
  8. 2015 あるいは 2013 で Xamarin.Forms のプロジェクト( Mobile Apps )を作成する。
  9. Debug 実行をして、一旦、Hyper-V に VS Emulator Android – Phone を作成する。
  10. Debug 実行のままだと、Connect エラーが出るので、一度だけ Release モードで実行する。そうすると、デバッグ用のコネクション( GetProcessId が取れるようになる)が確立されて、以後は Debug モードでも実行できるようになる。

ここまでやると、Visual Studio 2013/2015 で Xamarin.Forms を使ってアプリを作ることができます。

お次は Xamarin.Android でもビルドできるように C:Program Files (x86)MSBuildXamarinAndroidXamarin.Android.Common.targets を修正します。

<Target Name="_ConvertDebuggingFiles"
	Inputs="$(OutDir)$(TargetFileName);$(_IntermediatePdbFile)"
	Outputs="$(OutDir)$(TargetFileName).mdb" 
	DependsOnTargets="_ValidateAndroidPackageProperties">
	<ConvertDebuggingFiles InputFiles="$(OutDir)$(TargetFileName)" />
<!--	<Touch Files="$(OutDir)$(TargetFileName).mdb" />  -->
</Target>

デバッグ用の *.mdb ファイルを探してエラーになっているので、これをコメントアウトします。ファイルはメモ帳などを管理者モードで起動して編集してください(Visual Studio 自体を管理者モードで起動しても ok です)

この状態で、VS 2015 からエミュレータを起動して、VS 2013 を開くと、Target Android Deveice のに Hyper-V のエミュレータが現れます。

image

Debug モードでビルドをすると、デプロイ&デバッグコネクションのエラーになりますが、Release モードにすると正常にデプロイが完了します。ただし、残念なことにデバッグ状態では起動できないので、便利なブレークポイントなどの機能が使えません。まあ、そういう場合は Xamarin Android Player を使うということでよいでしょう。

あと、Hyper-V の Android Emulator は v4.4 が入っているので Xamarin.Android プロジェクトの設定を合わせておきます。

image

それと、Android Options > Advanced を開いてサポートする CPU に x86 を含めてください。Java のサイズとかはいつも通りに設定します(設定しなくても普通は動きます)。

image

単独で VS Emulator Android – Phone を起動する

これで Visual Studio 2013 から Hyper-V の Android Emulator を起動することはできたのですが、最初の起動を 2015 から行わなければいけないというのも変です。なので、単独で Emulator が起動できるようにしましょう。

image

WP8 のエミュレーターを単体起動するためのショートカット – 高橋 忍のブログ – Site Home – MSDN Blogs
http://blogs.msdn.com/b/shintak/archive/2012/11/06/10366015.aspx

実は、Windows Phone のエミュレータを起動する方法と同じです。VS Emulator Android は、

C:\Program Files (x86)\Microsoft Visual Studio Emulator for Android\1.0\XDE.exe

にあるので、実行ファイルを差し換えればよいでしょう。ヘルプ自体は xed.exe /? にすると表示ができます。

[Window Title]
Visual Studio Emulator for Android

[Content]
Emulator version 1.0.41108.1

Usage:
xde [/name vmname] [/vhd vhdpath] [/memsize sizeMB] [/com[1|2] pipeName] [/createDiffDisk diffVhd] [/language lcid] [/video widthXheight] [/diagonalSize screenSize] [/showName] [/noStart] [/snapshot] [/displayName text] [/fastShutdown] [/noALS] [/noFFC] [/noGyro] [/noMag] [/noNFC] [/softButtons] [/camera capability] [/?]

/name vmname: The name of the virtual machine. If you do not provide a name, the default ‘Default Emulator’ is used.

/vhd vhdpath: The path to the VHD for the virtual machine (required if the virtual machine does not exist).

/memsize sizeMB: The amount of RAM in MB that the virtual machine should use. Default: 512

/com[1|2] pipeName: The named pipe that the host uses to communicate with serial ports on the virtual machine.

/createDiffDisk diffVhd: Creates a differencing disk, using the path specified by /vhd as the base. The virtual machine uses diffVhd for its VHD.

/language lcid: The hex language ID to use for the emulator. This ID applies only to the host-side emulator application and not to the guest. Example: /language 040c

/bootlanguage lcid: The hex language ID to use for the emulator. This ID applies only to the guest-side OS and not to the host-side emulator application. Example: /bootlanguage 040c

/video widthXHeight: The initial screen resolution of the emulator application. Example: /video 640×800. Default: 480×800

/diagonalSize screenSize: Specifies the diagonal screen size for the emulator (in inches).

/showName: Displays the name of the virtual machine on the emulator chrome.

/noStart: Exits the program without showing the emulator (after creating or modifying the virtual machine).

/snapshot: Tries to boot to the default snapshot, or create a new snapshot if no snapshots are found.

/displayName text: The text to use for the application window and task bar icon.

/fastShutdown: Turns off the virtual machine without waiting for the OS to gracefully shutdown.

/noALS: Disables the Ambient light sensor.

/noFFC: Disables the Front facing camera.

/noGyro: Disables the Gyroscope.

/noMag: Disables the Magnetometer.

/noNFC: Disables the NFC sensor.

/softButtons: Enables the software buttons. (Not valid for all resolutions.)

/camera capability: Switches the camera to the specified capability mode. Valid capabilities: WP8

/?: Displays this help dialog.

私の環境では、/vhd と /video だけ指定すると動くので、/createDiffDisk しなくても良いかもしれません。

“C:\Program Files (x86)\Microsoft Visual Studio Emulator for Android\1.0\
XDE.exe” /vhd “D:vmVS Emulator Android – PhoneVirtual Hard Disksvsemulator.
phone.android.vhd” /video 480×800

な感じのバッチファイルを動かして起動させます。

image

/video の指定値は C:\Program Files (x86)\Microsoft Visual Studio Emulator for Android\1.0\skins にあるスキンのサイズに合わせれば大丈夫なはずです。それ以外は対応してないと思います。いくつか適当な値を入れてもエラーになってしまうので。

後は、Visual Studio 2013 からデプロイ先を指定すれば ok です。

カテゴリー: Xamarin | Visual Studio 2013 + Hyper-V で Xamarin.Android を動かそう はコメントを受け付けていません

Visual Studio 2015 preview を使って Hyper-V で Xamarin.Android を動かそう

現時点(2014/11/14)で Visual Studio 2015 はプレビュー版だし、Xamarin.Android はアルファ版を入れないとうまく行きそうにないので、うまくいかなくても仕方がないのですが…色々地雷があるので、回避方法(回復方法)をいくつか記録しておきます。

Visual Studio 2015 Preview の発表と共に Android のエミュレーターが Hyper-V 上で動くことが Connect(); で発表された(実演されている)のですが、結構限られた環境でないと動かなさそうな感じです。結論から言えば、私の環境では動いておりません…でしたが、Xamarin.Forms ならば動くことができました。

Visual Studio 2015 Preview をダウンロードする

Visual Studio 2015 Downloads
http://www.visualstudio.com/downloads/visual-studio-2015-downloads-vs

上記からダウンロードができます。まだプレビュー版なので、Hyper-V なり VMWare なりの仮想環境で試したほうがいいのですが、Android エミュレータ自体が Hyper-V で動作しているために、Hyper-V の中で Hyper-V を動かすことはできない/できなかった、ので実機 PC にインストールします。手元の環境では Visual Studio 2013 が入っている上に上書きをしたのですが、これはこれで嵌ります。ちなみに Visual Studio 14 TP が入っていると 2015 をインストールできないので、14 のほうはアンインストールします。

Xamarin.Android を入れる

Hyper-V で動く Android は Visual Studio からしか起動できません。Xamarin Studio からは従来通りの Andorid エミュレータか、Xamarin Android Player を使います。動かしてみるとわかるのですが、Hyper-V 版も Xamarin Android Player 版も速度はあまり変わりません。ただし、Windows Phone のエミュレート環境が Hyper-V であることと、Xamarin Android Player はリモートデスクトップ先では使えない(OpenGLが対応していない)ことが、Hyper-V 版を使ったほうが良い理由になります。

下記は、すでに Xamarin.Android をインストール済みなので、いくつかのテンプレートが表示されていますが、最初はひとつのテンプレートしかありません。

image

そのテンプレートを開くと Xamarin のページに誘導されます。田淵さんのブログにもありますが、Visual Studio で Xamarin.Android 開発を行うときは Bussiness ライセンス以上が必要になります。なので、プレビュー版であっても相当のお金を払っていないと試せないので、結構制限がきついかと。

こんなページが Visual Studio に出てくるので、Download Xamarin をクリックして指定ページに飛びます。

image

左の「Tell us a bit about yourself」に、名前やメールアドレス等を入れて XamarinInstaller-VS2015 をダウンロードします。ちなみに、ライセンスを持っている場合でも(Sign Inしている場合でも)、ここのリンクからダウンロードしなければいけません。

image

Xamarin.Android Update のアルファ版から入れられそうな気もするのですが、うまくいきませんでした。

ビルド時に MergeApkRecipelists なエラーが出る

これで 2013 と同じようにビルドができて Android アプリが作れるかと思い気や、いきなりビルドができなくてこけます。ブランクアプリを作ってもエラーが出るので、はっきり言って設定ミスです。

image

回避策としては、 下記にあるように、C++ のプロジェクトを作って参照設定させるとビルドが通るのですが、実はその後のデプロイに失敗するので意味がありません。

c# 6.0 – Getting Build Error Creating Android Application using Xamarin Extension for Visual Studio 2015 Preview – Stack Overflow
http://stackoverflow.com/questions/26902711/getting-build-error-creating-android-application-using-xamarin-extension-for-vis

どうやら、C++ ネイティブライブラリを必ず読み込むような設定にしてしまっているようです。これは早急に修正されるでしょう。ビルドしたものをデプロイしようとすると JNI のロードでエラーになります。そもそも、C# ライブラリだけを入れたいので、C++ は余計なだけだし、何故か思い余って Visual Studio 2013 に入っている Xamarin.Android にも影響を与えてしまうという悲惨な状態です。

image

解決策としては、Stable に設定し直してください、ってのが正解です。2013 のほうの Hyper-V でのエミュレータは使えなくなりますが、2015 preview のほうかは使えます(使えるといっても、エミュレータを起動できる、という状態なのですが)。

Stable に戻しても、2015 では Android アプリがビルドできない

実は Stable に戻した状態でも、2015 preview では Android アプリがビルドできません。

image

やっぱり、App5.dll.mdb とあるように、C++ のデバッグ情報を書き込もうとして失敗しています。なんだかなーという感じですが、native android はビルドできませんでした。

じゃあ、2015 preview では絶望的なのかといえば、そうではありません。Xamarin.Forms を使うアプリだとビルドができるんですよ。内部的にどうなっているのかわかりませんが(おそらく *.targets を直せばいいんですが)、Xamarin.Forms 用のプロジェクトを作るとビルドが通ります。

VS Emulator Android Phone にデプロイができない

ビルドが正常にできて、いざ Hyper-V 上で動かそうと思うと、一見うまく行きそうに見えますが…ダメです。

image

Hyper-V にインストールされた Android が起動はされるのですが、次のように Connect エラーになります。おそらく adb が Hyper-V 上の Android に接続しようとして失敗していると思うのですが、解決法がわかりません。以前、Android エミュレーターを動かしたときに、何度か遭遇しているネットワークエラーっぽいものなのですがね。

image

ちなみに、従来の Android エミュレータや Xamarin Android Player だと正常に動きます。なので、Hyper-V を使わない、かつ Xamarin.Forms に限定する、のであれば 2015 preview の状態で使えるのですが…いや、素直に 2013 に戻って開発したほうがよさそうです。

Visual Studio 2013 と共存していると拡張機能が 2015 preview に入らない

ここまで、さっくりと 2015 preview に Xamarin.Android がインストールできたように書いていますが、実は、2013 が入っている PC に 2015 Preview を入れると、拡張機能が 2015 のほうに入りません。

こんな感じに Xamarin Account のメニューが出るハズなのですが、最初はでなくて苦労しました。

image

以前、2010, 2012, 2013 が同居している環境でも同じことが起こっていましたが、

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Xamarin\

のフォルダにある拡張機能を Microsoft Visual Studio 14.0 にコピーします。3.9.41.0 のフォルダが、Hyper-V 込みなのですが、すべてコピーしてしまって大丈夫です。

コピーした後は念のために
C:\Program Files (x86)\NuGet\Visual Studio 2015\NuGet.Tools.vsix

を実行しておいてください。拡張機能の状態が更新されて、Xamarin Account の表示が出てきます。

2015 preview + android + Hyper-V は地雷が多い

そんな訳で現時点では、この組み合わせは地雷満載です。地雷を踏み抜く勇者だけが通れる道…つーか、デモでは通った訳なので、素な環境で素なプロジェクトを作れば意外とスムースに進むかなと。

Hyper-V で Xamarin.Forms を動かす手順

先に書いた通り native な Xamarin.Android はビルドエラーになってしまうのですが、Xamarin.Forms の場合は Hyper-V で動作が確認できています。通常の場合は、既に Visual Studio 2013 が入っている状態で、追加で Visual Studio 2015 を入れるでしょうから、ちょっと手順がややこしくなっています。
実機 PC は Hyper-V を動かす都合上、x64 版を使ってください。

  1. 実機 PC に Visual Studio 2015 preview をインストールする。
  2. 実機 PC の Hyper-V を有効にする(Visual Stuido をインストールした時点で Hyper-V が有効になっているはず)
  3. 最初の Xamarin Android プロジェクトを作って、リンク先から XamarinInstaller-VS2015  をダウンロード&インストールする。
  4. Visual Studio 2013 が入っている場合は、
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Xamarin\  を
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common\IDE\Extensions\ にコピーする。インストーラが Visual Studio 2013 のほうにしか拡張機能をコピーしないためです(これはいずれ直るでしょう)
  5. Bussiness アカウントでログインをして、Xamarin Update で Statble に戻す。
    2015 だけ使っている場合は不要ですが、2013 のほうの Xamarin.Android が動かなくなるのを回避します。
  6. 2015 あるいは 2013 で Xamarin.Forms のプロジェクト( Mobile Apps )を作成する。
  7. Debug 実行をして、一旦、Hyper-V に VS Emulator Android – Phone を作成する。
  8. Debug 実行のままだと、Connect エラーが出るので、一度だけ Release モードで実行する。そうすると、デバッグ用のコネクション( GetProcessId が取れるようになる)が確立されて、以後は Debug モードでも実行できるようになる。

image

この状態で無事、Xamarin.Forms のアプリが立ち上がります。

【速報】 Visual Studio 2015 Preview で Xamarin.Forms 開発が快適に! – Xamarin 日本語情報
http://ytabuchi.hatenablog.com/entry/2014/11/14/214918

田淵さんに先を越されましたが(苦笑)、二番槍ということで。

おまけ

Visual C++ で Android アプリが作れるようになりましたが、内実は Android Open Source Project です。Google の Android とは違うスタイルのオープンソースな Android ってことです。

image

Visual Studio のテンプレートを開くと OpenGL に特化しているらしく、おそらくゲームか画像関係のアプリを作るときに使うもののようですね。なので、C++/CX などのように C# と同じように Android アプリを作れるわけではありません。また、Xamarin.Forms を使うこともできないでしょう。Microsoft が C++ で Android 環境を提供するなんて…と思った方もおられるでしょうが、そういう訳で、もともと Android Open Source としてあるものを組み入れているし、得意分野も異なるので Xamarin 自体とは競合しません。むしろ、Delphi/C++ のほうとぶつけてきたという感じです。Delphi/C++ のほうでは、C++ で Android/iOS アプリが作れることを売りとしているので、そこが魅力的なところなのですが、Visual C++ でも作れるとなると開発環境を移す必要はなく、Visual Studio で統一できる、という結論に至ります。

これもデプロイ時にエラーがでるので、Hyper-V との接続がクリアできればいけそうです(つまりは、私の手元では動いていないのです…)

image

どうやら、一度 VS Emulator Android – Phone との接続を確立してしまうと、他の Debug モードも動くようです。上記の Android + C++ アプリも無事動きました。背景の緑の色が変化するサンプルのようです。

image

カテゴリー: Xamarin | 1件のコメント

Roslyn の活用しどころ

グロサミの最終日に Roslyn のハッカソンがあったので、午前中にちょっとだけ参加してきました。午前中だけなので、何をやるという訳でもなく、ざっくりと Roslyn Syntax Visualizer の解説を受けて、その後なにがしかの演習っぽいものをやるわけですが、いやいや、その前で抜けているので、ピザ食べて午後あたりになったときにどうなっているのかは分かりません。MS Store 行ってキーボードを買ってきて、お昼を食べて帰ってきて覗いてみたら、なんかまったりと Roslyn をインストールする感じだったので、駄弁るって感じだったんですかね?ハッカソンというものに出たことがないので、雰囲気だけ。

そんな中で、今岡さん(@imaoca)に力説した「Roslynは組み込みにも役に立つかもしれへんでー」という根拠をちらちらと書き散らしていきます。多少、希望的観測も入っているので実現が難しいところがあるかもしれませんが。

そもそも Roslyn ってどうやって使うの?

.NET コンパイラ プラットフォーム (“Roslyn”)
http://msdn.microsoft.com/ja-jp/vstudio/roslyn.aspx
Visual Studio “14”の新機能“Roslyn”とは – Build Insider
http://www.buildinsider.net/enterprise/roslyn/01
.NET Compiler Platform (“Roslyn”) – Home
https://roslyn.codeplex.com/

Roslyn が何か?ってのは、いくつかのブログで読めるので飛ばしてしまって、まずはインストールして使える状態にします。最後の https://roslyn.codeplex.com/ なところから、 Build tools that understand C# and Visual Basic な手順を順々に入れていけば OK です。

  1. Set up a box with Visual Studio “14” CTP 4. Either…
  2. Install the Visual Studio “14” SDK. You’ll need to do this even if you’re using the Azure VM image.
  3. Install the SDK Templates VSIX package to get the Visual Studio project templates.
  4. Install the Syntax Visualizer VSIX package to get a Syntax Visualizer tool window to help explore the syntax trees you’ll be analyzing.

Azure 上には Visual Studio 14 導入済みのものがあるので、それに 3,4 の VSIX をインストールします。そうすると、ファイルオープンなところに「Roslyn」カテゴリが増えるのと、

image

View → Other Windows → Roslyn Syntax Visualiser なメニューを選択すると、

image

CodeDOM が見れるようになります。

image

これをもとに、既存の言語に機能追加をしたり、解釈を変えたりするわけです。C# 自体の新機能も含まれているのですが、C#、VB のような特定言語よりも「コンパイラ」自体に興味がある人は、この機能が公開されて利用できる、ってところに注目します。つーか、私から見た目玉機能はこれですね。

構文木を作る lex/yacc

Roslyn の詳細な API はともかくとして、オープンソースなコンパイラであれば、gcc でもよいし、ruby でも python でも良いわけで F# だってソースが公開されています。gcc のコンパイラそのものを弄ることは少ないけど吐き出される as コードを見て C 言語レベルで最適化をかけたり(部分的にアセンブラを使うとか)するわけで、コンパイラがオープンソースになったところで、あまりインパクトは大きくありません。

IL に落とすという意味でも、そこまで突っ込むことは少ないし、そもそも C# や VB の文法をローカルに変えてまでやるぐらいであれば、別の言語を読み込ませるたり、F# のコンピテーション式のように DSL を埋め込んだりしても良いのです。また、C/C++ で適当なマクロを作れば、大抵のアセンブラ的なコード(行単位の命令コードの羅列)は書けます。別言語になってしまうという難点はありますが、ライブラリとして独立さればよい話で、混乱するような形になるならば、汎用的に作らずとも、R言語のように統計に特化させても良いのです。

そんなプログラム言語単体の話よりも(リファクタリング等の機能もあるのでしょうが)、Visual Studio という IDE の機能を Roslyn により使えるというところに私は注目したいのです。構文木(Syntax Tree)を扱う時に、内部的には CodeDOM のようなスタイルになっているのでしょう。なので、このスタイルに則ってコンパイラを書けば、そのまま Visual Studio の機能が使える…と思います。おそらく、F# は対応されるだろうから、そのあたりで Roslyn の実力を見てっところなんでしょうが。

懸念点と言えば、現在 C#/VB しか対応していないところから、C#/VB に似た言語スタイルでないと Roslyn の API は使えないのか?という点です。たとえば、LISP を Roslyn で通して、Visual Studio で編集できるようになるだろうか?とか、PHP や Perl のようなスクリプト言語の場合はどうなるのだろうかとか。Ruby や Python のほうは、オブジェクト指向言語だし過去に IronRuby な形で編集できるようにもなっているので、導入は比較的楽かもしれませんが。

また、既存の複雑な言語でなくても、ちょっとした DSL を自前で作っておいて、Roslyn に対応させておけば、Visual Studio で編集ができる(補完機能とかサジェッションみないな機能とか)可能せがあります。そうなると、自前でちまちまと専用エディタを作る必要もなくなるし、読み込ませ方によっては結構面倒な JSON や XML 形式で書きつけなくてもよい、ってことになりますよね(まあ、適当なスキーマを作れば JSON のほうが便利ってのもありますが)。

そういう訳で、 Roslyn が扱う CodeDOM(かな?)に直しさえすれば、Syntax Tree から派生する機能が使えるのではないか?と想像できます。

組み込み言語と Roslyn の関係

.NET Micro Framework の場合、C# が使えるから、そのまま Roslyn の機能が使えます。IL に落とす段階や、プラットフォーム毎の .NET のバージョンの違いなどは、Windows 10 で改良されるので(Microsoft.NET とか One.NET とかいうスタイルで)、C# で書いておけば組み込み機器でも動作する、というパターンにはできそうです。

現在、.NET MF は x86 と ARM しか対応していないわけですが、将来的に(過去的にも)マイコン系の CPU に対応させたり、あるいは各種の C言語コンパイラを Roslyn スタイルに直すことで、Visual Studio 上でビルドをすることも可能では?と思っています。あるいは C# でコンパイルしたものを IL に直し、IL 自体を独自の C ライブラリに直すとか、あるいは C# で書いた後に、独自 CPU に対応した IL(内部的には C言語コール)に直してしまうとか。これもローカルな言語を Visual Studio で動かせるようになれば、組み込み言語自体のコーディング速度も変わってくるはずです。まあ、最初のターゲットとしては Arduino 用の C 言語を Visual Studio 上でビルドできる、ってのが理想的ですよね。今でも専用エディタが付いているし、.NET MF を使えば C# で書けるのですが、うまくエディタと IDE が独立に動作して、かつ、コード分析レベルでは同期することができれば、そういうことも可能でしょう。かつて CodeWarrior が、多言語の開発環境を担っていましたが、あれと同じスタイルになると良いです。まあ、それでも Visual Studio で、ひとつのソリューションに複数の言語を入れて開発することができるので、かなり実現されているわけですが。

そんな訳で、ちらちらと Roslyn の中身を眺めなければ。

カテゴリー: 開発 | Roslyn の活用しどころ はコメントを受け付けていません

AllJoyn とは何だろうか?

いままで知らなかったのですが、AllJoyn という通信フレームワークがあります。IoT の中で中核を成す…というか、どうやってモノ同士で通信させるんだろうか?ってのは、C/S でも問題だし、P2P でも問題になるわけですが。

MS、IoTを推進するAllSeen Allianceに加入–クアルコムが主導 – CNET Japan
http://japan.cnet.com/news/business/35050321/
Open Source IoT to advance the Internet of Everything – AllSeen Alliance
https://allseenalliance.org/

実は AllJoyn というオープンソースな規格があって、Qualcomm が推進していることを先日のグロサミで知りました。PC から Raspberry Pi への通信とか、Raspberry Pi から BrickPi を通じて Logo のモータを動かしている訳ですが、自前の BrickPiNet では、REST で通信するようにしています。Raspberry pi の場合は、Linux が動いているので REST を Apache 上に作るか、HttpListener で作ってしまいます。動的にアセンブリをロードするわけではないので、HttpListener のほうでも楽に作れます。モーターを動かすとかセンサーを起動させるとか、そういう REST を送る訳ですが、このぐらいのものであれば、何か規格があっても不思議ではないよな…とは思っていたのですが。

それが、AllJoyn という規格です。規格自体は 2008年頃?で、SDK 自体は 2011年ぐらいです。現在は ver.14 で https://allseenalliance.org/source-code にアクセスすると各種環境の SDK がダウンロードできます。Qualcommが発起人で、現在は Linux 財団がオープンソースとして管理、ってな感じなんですかね。

何ができるのか?

各種 OS 間でデータ通信を行います。データ通信自体ならば TCP/IP をそのまま使ったり(特には IP だけ使ったり)、最近の機器では組み込み系の Linux が入っているから Apache を入れて応答を返すってのが普通に行われますが、Android や Phone やら、TV やオーディオ、冷蔵庫などまで範囲を広げます。相互に通信をできるようにする訳ですから、なんらかの規格を決めないといけません。

  • データ自体は、XML で送受信
  • データ内容は Get/Set などシンプルなメソッドを使う

途中に AllJoyn のルータなどが挟まるのでネットワーク的には複雑なのですが、EndToEnd 視点ならば非常に単純です。Pull と Push の両方の機能を備えるので、端末機器からの Event 通知を受けることができます。このあたり、SNMP の MIB に近いのかなと思ったりするのですが、どうでしょう? MIB 自体はバイナリと IP を扱わなくて結構大変なのですが、現在の端末機器の CPU とメモリを考えれば XML データを流してエンコード/デコードしてもパワー的に十分ですよね。

https://allseenalliance.org/developer-resources/alljoyn-open-source-project にあるメニューリストを見ると、Unity や Windows 7 が入っています。ゲームの双方向通信にも使われているらしく、Unity + AllJoyn で作っておけば、WiFi/Bluetooth 環境にあるゲーム機器が、機種に関係なく相互通信ができるのでは?と思ったりするのですがどうなんでしょう。

また、先に書いた通り、シンプルな XML をデコードする機能さえあればいいので、.Net Micro Framework のような非力な機器でも使えそうです。データの内容を見ると SOAP のように名前空間を使っていません。

プログラム言語は、Java, Objective-C, C++, C#, C で扱えます。https://allseenalliance.org/alljoyn-framework-tutorial C# で扱えるんだから、F# とか VB でも扱えるでしょう。

具体的にどうやるのかは、これからチュートリアルなどを読んでいくわけですが、クラス名もこんな感じでそう多くありません。

image

BusLitener と SessionListener が肝な感じがします。

ひとまず、自分用のメモまで。

カテゴリー: 開発, AllJoyn | AllJoyn とは何だろうか? はコメントを受け付けていません

MVP Global Summit 2014 感想戦

MVP Global Summit
http://mvp.microsoft.com/summit

MVP 自体は 4年目なのですが、Global Summit に行くのは初めて。さっくりとツアーで行ってツアーで帰ってくるつもりだったのですが、同室の方の都合で最終日まで Red Lion に1日伸ばしでした。セッションの会場はマイクロソフト社内なので、ホテルからバスで送迎だし市内から遠くてもあまり変わらんですよね、安いし(ツインで120$ だったので、延長分はひとり頭 60$ でした)。

初日のベイエリアの観光以外は最終日の午後にベルビュースクエアを回ったぐらいで、碌な観光もせずに勉強会のノリで行ってきました。ぎっちり、3日間ひとりでセッションを回ってきたのでほぼ英語漬けの毎日ですが、なんか、あのスピードの英語ヒアリングはつらいです。スライドとかデモをやっているときはいいんだけど、ディスカッションになって(スライドの途中でも容赦なく質問をして、容赦なくディスカッションになってしまうあたり欧米風なのか、やっぱり言いたい MVP さんがたくさんやってきているのか)しまうとかなり辛い感じ。GAG のところが笑えないのは、今後ヒアリングを第一に勉強しようという原動力にはなるかもって感じです。やっていることは、所詮コンピュータ関係なので、概要は聞き取れるし、込み入って難しい話になればこれは英語でも日本語でも難しい話になってしまうので、同じことです。セッション中に手を上げて、スライドの途中でも止めてしまうスタイルは、.NETラボで発表するときにでも取り入れていきたいですね。スライドを淡々と読み上げると眠くなってしまうので、デモを交えてという工夫をやるのですが、質疑応答…というか議論自体が間に挟んでしまえばスライド自体ほとんど要らないという利点もあります。あと、顔を合わせている「勉強会」なりのメリットもあるでしょう。

F# のランチセッションで、替え歌に合わせて OWIN を解説するってことをやっていました。以前、プロ生で西山さんがギターの弾き語りセッションをやっていましたが、ああいうノリもありかなと思ってます。日本の勉強会だと世代差が気になる感じだけど、グロサミに出て手を上げているガリガリ質問しているのは50歳以上っぽい人(私よりちょっと上ぐらい)だし、そういうかき回し方もよいでしょう。

私が主に行ったのは、IoT のセッションです。Visual C# ってところで、ASP.NET vNext と Roslyn 、Xamarin はちらっと回ってきて、後は IoT に入り浸っていました。セキュリティ F# セッションってことで、てくてくと雨の中を歩いて聞いてきましたが(10人ぐらいいて、部外者が2人な感じだったよw)、ほとんどは Embedded のところです。Microsoft Band のページを調べていて、話しかけてきたおじさんに(自分もおじさんですが)、Raspberry Pi やってて、これから Spilder で勉強するつもりなんや、って話すと、Splider でバーベキューの温度を測る機械を作っている(らしい)ページを見せてみせてもらいました。あと、なんか前のほうで、Not NDA のページをセッション資料を作っている人がいるなーと思ったら、最後の LT(10分ぐらいのミニトークで、MVP が発表する)で、組み込み機器は「Wife のように扱えるといい」(英語を忘れました)という、ヒーターとかオートロックとかをまとめて Windows Phone のアプリにしたりしている人でした。「Wife のように~」のところで、皆が爆笑しているのであれは流行り(独身が多い?)なのかも。組み込みの場合は、年齢層が高.くて、Windows CE、Windows Mobile から、Windows XP Embedded な人が多いですね。完全に組み込みな、.NET Micro Framework のときは質疑応答が少なかったので、少しジャンルが分けられているようです。

codenameathens

Microsoft’s fitness band: What kinds of software and services are inside? | ZDNet
http://www.zdnet.com/microsofts-fitness-band-what-kinds-of-software-and-services-are-inside-7000035344/

Windows 10 に統合して、4つの分野に Framework を分ける、っていう話は、Tech Ed Europe で発表されているもので、NDA ではありません、よね。Windows Phone や 従来の Surface RT のような Windows RT は Windows 10 “Mobile” になって、従来の .NET Compact Framework は、Windows 10 “Athens” になるってことです。更にコンパクトになっている組み込みに使う .NET Micro framework は通りに使われる感じです。Microsoft Band の UI は、Windows 8.1 のスタート画面風なので、Embedded 8.1 か Windows Phone ベースなのかなと思っていたのですが、スライドを見るとそれっぽい時計の絵が描かれているので、ひょっとすると .NET Micro かもしれません。.NET Micro は情報だけはちららと追っていたのですが、今年の夏にやっとこさ Splider を買ったぐらいで、netduino の存在は知らなかったんですよね。

2010年頃にすでに発表があって、日本で買えたりしてました。「してました」って過去系になっているのは、スイッチサイエンス社が在庫切れになったままで、新しい netduino plus 2 を扱っていません。コネクタ等が arduino 互換なので、外部機器を共用するならば netdouino のほうがいいかなと思っています。まあ、コードの接続がややこしいですが、ハルロックを読んで頑張りましょう(ちなみに、ハルロックには基板解説とかは出てこないので、やる気だけを貰うということで)。

日本の IoT と海外の IoT の違い

Microsoft 技術からの視点なので、本格的に Raspberry Pi とか Aruduino から見たら(半田付けする、という点で)違うかもしれませんが、グロサミに行った感じでは、日本と海外(欧米)とでは結構違いがあります。

私は Kinect や Leap Motion を扱わないので(あと Oculus Rift DK2も)そのあたりはよくわからなくて、日本の組み込み系は MS太田さんオンリーなのかなと思っていたりするわけですが、Raspberry Pi や Aruduino で何かモノを動かそうと思うと、もうちょっと周辺の器械を活用しないと駄目ですよね。さきほどの MVP ライトニングトークスで出てきた、デカいモーターや、ごついドライヤー(温度センサーを温めるらしい)、デカいタッチディスプレイを担いでくるあたりが、海外の IoT さんの面白いところです。

確かに、Windows Phone を買ったり、Surface Pro を買ったりするのもいいんですけど、同じ値段ならば、Rspberry Pi を買ったり、Aruduino 用のセンサーを買ったりするほうが、「よりたくさんの機器が買えるんですよッ!!!」。まあ、センサーにも色々あって結構な値段はするし、Lego Mindstorms EV3 は Windows Phone と同じぐらいの値段になるので、どっちを買っても一緒ではあるのですが(苦笑)。

そんな訳で、日本の IoT は、Internet のほう(Windows Phone とか Surface とか)から入っている感じがしますが、欧米の IoT は、Thing のほうから入って来てます。周辺機器の豊富さもあるのかもしれませんが、もともとある DYI の精神なのかな、と思ってます。家のガレージに工具を置くことあができたり、広い公園でラジコンやロケットを飛ばしたりするのが普通の環境じゃないと、あの発想はできないのでは?ってな感じです。

じゃあ日本はどうやって IoT というジャンルを確立していくのか?というと、同じ方面じゃなくてもよくて、ロボットでも踊りでもARでもVRでもよいのですが、もうちょっと海外と対抗するような視点を持ってモノを作ってもよいかなと思いました。Oculus も初音ミクもMMDもすごいといえばすごし、そこそこ手軽に実現ができるようになってるし、日本でやっている人が多いから日本語で情報が得られるので、初手としていいのはいいのでしょうが、そのまま海外(欧米)に持っていくと違和感アリな感じです。それを日本独自の文化と捉えるか、違和感のまま捉えるか、ってのがあると思います。勿論、日本のアニメ文化の延長上でという感覚もあるんですが。

そんなこんなで、自分としては今まで通りニッチなところかつ、海外で受け入れやすいスタイルで、Raspberry Pi を扱っていきます。いつかの IoT のセッションを見ていくと、海外(欧米)が特に進んでいるという訳でもないし(同時に日本が取り残されている訳でもないし)、いくつかの面では高速道路も準備されて、マス的な Microsoft Band のような当たりを日本で作るのは難しいでしょうが、もっとバリエーション(機器の組み合わせてという意味で)を作って、それを実現するときに、.NET Framework + Xamarin + Raspberry Pi/Netduino  + AllJoyn のようなスタイル確立できるかな、と思って帰ってきました。ひとまず、.NET Micro framework が動く netduino を試してみるのが初手、つーか、その前に FEZ Spider Starter Kit ぐらいは開封せねば。

英語のヒアリング

ディスカッションをするには、英会話が必須なんですが、TOICE 300点前後(程度だよ。たぶん。10年前ぐらいだけど)の自分としてはヒアリングをやらないといかんと痛感です。たまに channel 9 とか TechEd の画像を流しっぱなしにして仕事をしていますが、スライドとは関係ないところで話をしていると途端に分からなくなります(キーワードを拾い集めて、おおまかな意味から推測するってことをやっているので)。コンピュータの本は洋書が多いし、MSDN で英語文にあたることが多いから、英文をざっと読み込むことはできるし、英文を書くときは Google 翻訳を使ってほぼコピペで流すことはできるのですが、カンファレンスのヒアリングは難しいですね。自分の後ろの席で、自動翻訳っぽい音が聞こえた(英語じゃない言語で、ちょっと遅れで話している感じ)ので、そんなのを使うのもアリなんでしょうが、やっぱり、英語は英語のまま理解するほうが脳への負担は少ないと思われます(疲れにくい、退屈して眠りにくいっていう意味で)。

レッドドワーフ号のイギリス英語のほうが少しわかりやすいけど、アメリカ英語と聞き取りづらいのはなまりの問題もあるかなーと思うけど、まあ、すべてとは言わなくても半分ぐらいは英語のまま理解したいですよね。お金を払って英語のセッションに行って、英語が聞き取れなかったら意味がないわけで(グロサミ自体は MS が会場費を持ってくれているけど、日本からの旅費は自前だし)、これは早急にやり始めないとという感じでした。

因みに、日常的な英会話も不便な私ですが、相手に話すときは「文法通りに話す」と意味が伝わりやすいです。文法通りってのは前置詞あれこれってのもあるのでしょうが、SVO を守って、3単語ずつしゃべればだいたい通じます。どう聞こえているか分からんけど、相手にとっては外人だから許してくれるでしょう。…つーか、経験上、意図を正確に伝えたいときは文法通りに、雰囲気を伝えたいときはジェスチャーでって感じ。ビジネスのときは困るだろうけど、街中歩くときと、同じプログラマの人と話すときはこれで十分かと。

カテゴリー: 開発 | MVP Global Summit 2014 感想戦 はコメントを受け付けていません

XAML とは何か? … Microsoft だけのものじゃない

XAML を勉強しておけば将来役に立つよ…と Microsoft 様よりお達しがあって久しいのですが、そもそも、XAML ってのは何?ってのが昨日気になって調べていました。データの形式だけで見れば、XML 形式なのですが、あえて「XAML」とするところに意味はあるのか?かつ、Xamarin.Forms で使われている XAML は XAML と言えるのか?って話です。

Japan Xamarin User Group (JXUG)
https://www.facebook.com/groups/xm.jxug/
Using Workflow Markup
http://msdn.microsoft.com/en-us/library/vstudio/ms735921(v=vs.90).aspx

榎本さんの話で、Xamarin.Forms 以外にも WF(Workflow)でも使われているそうです。中身を見ると、XML でも良いような気がするけど、なぜに XAML なのか?

XAML は仕様が公開されている

結論から言えば、XAML の仕様は公開されています。Microsoft 自身が MS-XAML として公開していて、それに基づいて WPF やストアアプリの XAML を作っています。当然、WF の XAML も作っていて、同じように Xamarin.Forms の XAML もこれに基づいている(ハズ)です。

XAML 構文の詳細
http://msdn.microsoft.com/ja-jp/library/ms788723(v=vs.110).aspx

の中にある MS-XAML をクリックすると、公開しようの PDF に至ります。Silverlight などの XAML は以下でも公開されています。

Microsoft Domain-Specific Languages
http://msdn.microsoft.com/en-us/library/dd361847.aspx

ついでに言うと、Excel のファイルを保存したときにできる .xlsx の形式とか、VBA の仕様とかも公開されています。Microsoft は、この公開情報に基づいてデータを作っている(あるいは拡張している)ので、まあ、Office データの互換フォーマット率なんかは、このあたりを元にすれば適切かなーと思ったり。

XML と XAML の違い

SPEC をざっと読むと、いくつかの違いがあります。XAML ⊂ XML な訳だから、XML の形式に基づいてはいますが、いつかの拡張があるってことです。

  • namespace で http://schemas.microsoft.com/winfx/2006/xaml が必須
  • x:Class で実クラスにマッピングする
  • tagName.propName のように、ドットでつながった名前が特別扱い
  • attrName=”{Binding xxxx}” のような、属性値に {…} を指定したときに特別扱い

他にもいくつか細かい違いがあるのですが(「Name と x:Name を同時に定義してちゃいけない」という仕様がある!)、まあこんな感じです。

WPF やストアアプリ、Windows Phone で規定されているコントロールとかは XAML 本体とは別ものなので、Xamarin.Forms の XAML の共通部分も、ここの MS-XAML にあっている(はず)です。

名前空間 http://schemas.microsoft.com/winfx/2006/xaml を利用

XAML では x:Name のように、x 付きの属性が頻発するのですが、これが XAML の肝っぽいですね。名前空間のエイリアスが「x:」でつけられているのですが、「xxx:」のように変更することも可能です。

乱暴なことを言えば、このスキームを設定するだけで、XAML です、と言い張ることもできる…かもしれません。あまり意味はありませんが。

x:Class で実クラスにマッピングする

XAML は、XAML ファイル単体で存在するとは少なくて、特定のクラスとマッピングされます。XAML 内にある x:Name を x:Class で指定したクラスのフィールド(プロパティでも良い?)やイベントにバインドしています。なので、特にバインドしない場合は、x:Class を書かなくても良いと思うのですが。このバインド自体が、*.g.cs のようなバックグラウンドのコードを吐くので、ビルド環境依存になるような気がするんですけどね。このために Visual Studio で普通の C#/VB の XAML を書いたときにはバインド用の中間ファイルが作られます。F# の場合は、この中間ファイルを作らない(作れない?)ので、x:Class を指定せずにタイププロバイダを使うという方法を取っています。

ちなみ、自前の XamarinForms のプレビューアは x:Class を指定しているけど、動的にクラスをバインドするという手法を取っていて、動的なコードを作りません。なので、XAML 解析コードを自前で作れば、ちょっと違ったマッピングの仕方もできるということです。

ドットでつながった名前を特別扱いする

XAML を調べていた理由として、このドット付きの名前があります。<TextBlock Text=”…” Grid.Row=”0″ のように、親の Grid に設定をしたり、<TextBlock.Background>Black</TextBlock.Background> のようにプロパティを設定したりできます。ドット記号自体は名前に使ってよいことは調べたのですが、このドットの前後を SPEC で規定しているのか否か?ってところです。

MS-XAML を見ると、6.5.1. DottedXamlName として、ドット付き名前が規定されています。これに基づいて、ドット前後の XamlName に分けて XAML 解析を行うという訳です。

属性値に {…} を使う

XAML の拡張として、属性値に {…} が使われているのですが、これはどういうフォーマットなのか?自由フォーマットなのか?と思っていましたが、これも MS-XAML で規定されています。

6.6.7.1. Markup Extension Parsing なところで、MarkupExtension としてフォーマットが決まっています。なので、Text=”{Binding text}” のような感じなのも勝手なフォーマットを使っている、という訳ではないのです。

XAML 形式を解析する

Xaml ファイルをロードしてマッピングする場合は、XamlReader を使います。ストアアプリのような WinRT の場合は、いかな感じで読み込みます。

[WinRT] XElement を使い XAML を構築して動的に XamlReader.Load で読み込む技 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6556

WinRT の場合、Windows.UI.Xaml.Markup 名前空間にあるのですが、WPF のような本来(?)の XAML は、System.Xaml の下にあります。何故、System.Xaml から動いてしまったのか、Xamarin.Forms に System.Xaml が無いのはなぜなのか、は分かりませんが、処々の事情がありそうです。

  • XamlXmlReader
  • XamlObjectReader
  • XamlServices

XAML 解析とマッピング自体は上記の 3つのクラスを使えばよさそうです。Read メソッドで SAX 風にタグを読み込んでマッピング部分を自前で書いていけばよいのです。Xamarin.Forms プレビュアは、XML として読み込んだ後に、独自に解析をしているので、このあたりを変えたいな…とは思ってはみたものの、Xamarin.Form には、というか mono には System.Xaml がないんですよね…ともったらあるよ( http://www.mono-project.com/archived/systemxamlhacking/ )。ストアアプリ WinRT のほうにも System.Xaml がないので、互換ライブラリを作って PCL 化するのがいいんですかね。

ここまで書いて、一切 UI な部分が出てきませんが、そうなんです。XAML は UI とは全く関係ないんですね。ってことは、普通にクラスにマッピングする XML 形式のデータであればよいのです。なるほど。

連載:Windowsストア・アプリ開発入門:第5回 データを画面に表示する (1/5) – @IT
http://www.atmarkit.co.jp/ait/articles/1311/01/news095.html

のように、デザイン時のデータ形式は、JSON と XAML が選べます。そうなんです。XML じゃなくて XAML なんですよ。これは、まあ、そういう意味があるということです(逆に言えば、クラス構造を外して、JSON のように XML 形式でも十分ではないか?とも言えますが)。

カテゴリー: XAML | XAML とは何か? … Microsoft だけのものじゃない はコメントを受け付けていません

TDD cannot Die. TDD は死ねません。

【翻訳】テスト駆動開発(TDD)はもう終わっているのか?PART I | POSTD
http://postd.cc/is-tdd-dead-part1/
【翻訳】テスト駆動開発(TDD)はもう終わっているのか?PART II | POSTD
http://postd.cc/is-tdd-dead-part-2/
2014-10-27 – やっとむでぽん – TDDの経験と現状のアンケート
http://d.hatena.ne.jp/yach/20141027

アンケート自体は「TDDに関心がある人」のフィルターが掛かっているので、数値そのものは意味がないのですが、傾向がわかります。私の場合、JUnit が出た当時から使っているので(その頃は CppUnit でテストしてた)かれこれ10年ぐらいやってます。最初のテストフレームワークは、自前の Excel VBA で C++ の自動テストをする、という自作 xUnit もどきを作っていて、その直後、Ruby の UnitTest から入ったぐらいですから、かなり初期の頃の TDD から入っています。XP のプラクティスのひとつとして、テストフレームワークと自動テストは必須だったので、それを最初に取り入れます。あらゆるテストを xUnit でやろうとした頃もあるのですが、UI 系のテストは諦めることにしています。というのも、「作業量に見合わない」作業をやっても仕方がないですから、の結論に至ります。

自前のライブラリを作るときや仕事でも TDD を使います。いや正確にはテストファーストではないのですが、大抵はテストコードを書いてから、それに合わせるようにライブラリを作ります。このあたりは、自前の UIDD (ユーザインターフェース駆動開発)のひとつで「見た目使いやすいものが、後後になっても使いやすい」に基づいています。

さて、そんな中で記事のタイトル通り「TDD は死ねません」≒ 死ぬことができませんな話を書き下しておきましょう。

何のために TDD を使うのか?

「プログラマの精神の安定のため」ではあるのですが、仕事なので「作業量」を少なくするため、という目標を掲げます。トータルの作業量が増えてしまえば(保守やリリース直前の不具合対応も含めて)、テストをやっていても自己満足にしかなりません。ちまちま一行プロパティをテストするのも「単体テストの行数を稼ぐ」という目的は達せられるでしょうが、最終的な目標は達成できません。どうやったってテストに合格するテストコードは書いても意味がないんですよ。なので書きません。

テストコードが複雑怪奇になって、テストコードの保守が大変になって、オブジェクト指向もどきのクラスライブラリが氾濫して自動テストをやるたびに、テストコードをあれこれと変えてやらなければ進まないのであれば、ざっくりとテストコードは捨ててしまいましょう。最終的な工程になって、手作業で UI を操作しなければうまくテストができなければ、自動テストをちまちまメンテするのは止めましょう。もっと、やらないといけないことがあるでしょう?ってな話です。

いわゆる、xUnit 的なツールは「治具」です。最終的な製品には含まれないけど、製品を精度よく作る、効率よく品質を上げるための「使い捨てのツール」です。なので、プロジェクトの横断するような自動テストを妄想するよりも、プロジェクトに密着したテストツールを、プロジェクト単位で作るほうがベータです。所詮「治具」なのです。だから、プロジェクトに密着したときにはじめて効果があるし、逆に言えば、他で便利だからといって自分のプロジェクトで便利とは限らない。そういう場合は、捨ててしまうし、そういう意味では、TDD is dead. なプロジェクトもあってもおかしくないのです。

そんな訳で、効率よく製品を仕上げるために TDD を使う、ってのがひとつの到達点です。適用範囲があるってことですよ。

何故 TDD は死ねないのか?

簡単です。TDD で作ったテストツールは、製品/成果物を裏で支えている訳ですから、製品が生きている間、それに密着したテストツールは生き続けます。と同時に、製品が死ねば、テストツールも死ぬ訳です。

製品やライブラリに何か新しい機能を付け加えるとしましょう。それが、テストコードにかなうものなのか、テストコード自体を破壊してしまうものなのか、という問題があります。テストコードは、適用範囲が決まっている(修正以前の製品に対して、の責務しかない)ので、新しく追加した機能に対して、テストコードの振る舞いは未知数です。いや、正確に言えば、機能追加について、2つの方法が取れます。

  • テストコードを破壊するような、機能を製品に追加する。
  • テストコードに適うような、機能を追加する。

後者のテストコードに適うような機能追加は、比較的簡単です。また、こうすることが TDD を利用する最大のメリットでもあります。既存のクラスやライブラリを壊さないように「再利用できる」ように機能を追加してきます。なので、既存のクラスやメソッドの振る舞いを変えないように注意深く作っていきます。この方法は、土台を固めて上に付け加えるように作っていく方法なのですが、デメリットもあります。複雑な内容に複雑な内容を追加していくために、最終的に複雑すぎるものができあがってしまいます。初期設計が悪いと、べたべたと回避するコードやメソッドばかりがちりばめられてえらいことになります。

そんな訳で、私たちは TDD is dead. と叫んで、テストコードを捨てます。以前のテストは設計思想が古いので、すべてを捨ててテストコードを書き直さないといけなくなります。クラスの設計をちょいちょいと直したいのに、膨大なテストコードを時間をかけて直すなんてナンセンスです。

でも、ちょっと待ってください。以前のテストコードを捨て去っても、また新しいテストコードを書くこともできますよね。所詮「治具」なのですが、新しい設計のクラスに見合ったテストコードを書けばいいだけです。つまりは、テストコードは、設計が死ぬとテストコードも死ぬのです。逆に言えば、設計が生きている限りは、テストコードは生きています。

テストコードを減らす努力をする

ちょっと考えてみましょう。TDD is dead. と叫んで、テストコードを投げ出したくなる理由は何でしょうか? テストそのものが嫌い? TDD 自体が嫌い? それはそれでよいのです、テストが嫌いならば、テストの無い形で MDA スタイルで作ることも可能です(それはまだ、夢物語な時代ではありますが)。テスト自体をやめてしまう、という方法もあります。しかし、逃れられないテストであるならば、何かと省力化する、あるいは効果の高い方法を取るほうがよいのではないでしょうか?

効率的なテストコードは、パレートの法則よろしく、全機能の 20% にだけテストコードを書きます。微々たる些末なコードにまでちまちまとテストコードを割り当てておくには、プログラマの人生は短すぎます。ランダムテストで自動化するとか、コードレビューで回避できるものも多いでしょう。なので、ユーザーインターフェース(クラスやライブラリを使う側の視点)でテストコードを書いていきます。

使う側の視点でテストコードを書くと2つのメリットがあります。

  • 利用しにくいメソッドやクラスを排除できる。
  • ヘルプ/サンプルとして利用できる。

既存のクラスライブラリを使うときに、あれこれと前提の設定があって、こっちのメソッドを先に呼ばないと次のメソッドを呼び出せないとか、メソッドの順番に依存しているクラスとかがありますよね。TDD のテストコード自体、オブジェクト指向設計に基づいているので、クラス同時は疎結合でないとうまくテストができません。複雑に絡み合ったクラスや機能の場合、長い手順を踏まないと呼び出せない UI みたいなものを自動化するのは大変な努力が要ります(もちろん、その努力に見合う、対費用効果があれば取り入れるでしょう)。そういう心理的な効果、行動経済学な考えからして、使いづらいライブラリを使いづらいまま作るのは、利用者のデメリットなんですよ。Microsoft のドックフードシステムってのもありますが、それのテストコード版です(にしても、.NET Framework で多々使いづらいクラス設計があるのは内緒です)。まずは、利用者の視点になってクラスを作ってみましょう。色々なパターンもあるでしょうが、あれこれとクラスを組み合わせ作る悪癖はやめましょう。それは、効率的なテストコードを作れなくする第一歩です。

利用者視点から作られたクラスは、そのままヘルプになります。テストコードがあれば、大抵のサンプルコードが要らないんですよ。逆に言えば、サンプルコードが簡単にかけなければ、テストコードも書けません。それほど複雑なもの(外部要因とか接続タイミングなどがあって、簡単にテストコードが書けないものは多々あります)の場合は、TDD に向きません。ちまちまとテストをしてください。また、テストコード自体をユースケースとして作ることも可能です。うまくクラス設計をやれば、UI なしでユースケースをテストコード内に埋め込むことができます。当然、うまくないクラス設計の場合は、複雑怪奇になって破たんします。クラス設計のリトマス試験紙にもなるのです。

複雑なモックアップを作らないと動かないテストコード自体も、避けるのがベターです。私自身もいろいろなプロジェクト単位で色々なモックアップを作ってきましたが、結局のところ、本番の DB 構造を使ったほうが便利だったり、試験環境を作ってガンガン廻したりするするほうが、複雑怪奇なモックアップを作るよりも作業効率がよいです。目標は「製品を品質よくしあげること」なのですから、まずはそれを第一に考えます。

そんな訳で、テストコードがガンガン減ります。以前は、「元コードの3倍ぐらいないと、テストの品質は保てない」と公言していましたが、訂正します。テストコードは1行だけでも ok です。ユーザー視点のテストコードが少しだけあれば、それに合わせるようにプログラムを品質よく上げる環境が、現在では揃っています。インテリセンスを効かせたり、自動生成コードを使ったり、手作業の部分を減らしていけば確実にテストコードも少なく済みます。

最初にテストコードを書く

自前の ExDoc ライブラリには実にチープなテストコードしかついていません。実は、元ネタは 2年ぐらい前に作って、最近ふたたび機能を追加し始めました。巷の OSS なコードには大量なテストコードがあるのが普通なのですが、私の場合は面倒…じゃなくて作業効率を考えて少しだけのテストコードを書いています。

public void TestLoad()
{
    var xml = "<root><person name='tomoaki'>masuda</person></root>";

    var doc = ExDocument.LoadXml(xml);
    Assert.AreEqual("root", doc.Root.Name);
    // seek element
    ExElement el = doc * "person";
    Assert.AreEqual("person", el.Name );
    Assert.AreEqual("masuda", el.Value);
    string val = el % "name";
    Assert.AreEqual("tomoaki", val);
}

このテストコードを満たすように、ライブラリを作っていきます。結局、何をやりたいのかを先に決めておかないと、あれこれと無駄なクラスやメソッドばかりが増えていきます。このあたりは TOC(制約理論)の精神で、目標を決めて行動範囲を明確にする、っていう枠組みです。これが動作するためのコード自体はあれこと1000行弱ぐらいあるのですが、それぞれのテストコードは書いていません。必要があればちまちまと書いてもいいのですが、自己満足にしかならないので書きません。

逆に言えば、このひとつのテストコードが ExDoc というライブラリの動作を決定しています。それ以上でも以下でもありません。このテストコードを破壊するようなコードは ExDoc にもありませんし、破壊するようなコードを追加するときにはテストコードも死に、ExDoc の本体も死にます。それは別のクラスライブラリとして再出発したほうがいいですよね。

そんな訳で、オブジェクト指向設計をしている限りは TDD は有効だし、MDA のような別の手段が出てくるまでは TDD のほうが効率的です。勿論、WEB サイトを作るような時には不便だし、そこには踏み込めません。だって、WEB サイト自体はオブジェクト指向設計ではないのですから、もっと別なアプローチが必要でしょう? アプローチとしては、MVVM とか MVC とかテストしやすいように設計を組み立てることが必須です。テストしにくいものを無理矢理 TDD する必要はないし、TDD しても効果が上がらなそうなものに対してテストコードを大量に書くには、プログラマの人生は短すぎますからッ!!!

カテゴリー: 雑談 | 2件のコメント

ヒアドキュメントっぽく Yaml を書くための ExDoc.Yaml をリリース

Yaml を利用して C# でヒアドキュメントを考える | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6560

これの実装編です。Yaml をパースするためのライブラリが SharpYaml にあるので、これを使います。最初は、YamlDotNet を利用して作っていたのですが、 PCL 版がないので SharpYaml を使っています。SharpYaml 自体が YamlDotNet の派生ということなので、中身は同じクラスが使われています。

github

moonmile/ExDoc
https://github.com/moonmile/ExDoc

コードは github で公開していて ExDoc の下にあります。ついでに、HTML と Json 版も作りました。

  • ExDoc.Html – HTML から XML へ
  • ExDoc.Yaml – Yaml から XML へ
  • ExDoc.Json – Json から XML へ

拡張メソッドを使って、XDocument を生成します。そのまま XDocument で LINQ しても良いし、ExDoc に読み込ませて検索してもよい、というスタイルです。ExDoc 自体は XElement に依存しているので、検索結果を XElmenet に戻すことも可能です。まだ実装してはいませんが、そのうち属性や要素の値を変更して出力するようにもしていきます。

NuGet

nuget は、それぞれのアセンブリを別々に用意しています。

Moonile.ExDoc
https://www.nuget.org/packages/Moonmile.ExDoc/
Moonmile.ExDoc.Html
https://www.nuget.org/packages/Moonmile.ExDoc.Html/
Moonmile.ExDoc.Yaml
https://www.nuget.org/packages/Moonmile.ExDoc.Yaml/
Moonmile.ExDoc.Json
https://www.nuget.org/packages/Moonmile.ExDoc.Json/

もともと、Yaml や Json は XML にコンバートするメソッドを持っているのですが、いまひとつ使いづらい XML を吐き出すので、コンバートライブラリはそれを補足する感じです。設定やヒアドキュメントは人間に書きやすく、内部処理するときは XML 形式にしてプログラミングでやり易く、という主旨ですね。

ExDoc.Yaml の使い方

[TestMethod]
public void demo1()
{
    var yaml = @"
app:
- user: masuda
- apikey:  key-xxxx
- apipass: password
";

    var ys = new YamlStream();
    ys.Load(new StringReader(yaml));
    var xdoc = ys.Documents[0].ToXDocument();
    var doc = ExDocument.Load(xdoc);

    string apikey = doc * "apikey";
    string apipass = doc * "apipass";

    Debug.WriteLine("key:{0} pass:{1}",
        apikey, apipass);
}

たとえば、こんな感じで、yaml をヒアドキュメントで定義しておきます。このぐらいだったら、フィールドを使った方がいいし、そもそもアプリケーション設定を使えってのもあるでしょうが、まあ、テストの時とかちょっとした設定を書いておくときに便利でしょう。Yaml 自体はファイルから読み込みもできるので、外だしにしておくこともできます。

YamlDotNet/SharpYaml で作成したオブジェクトを直接参照してもよいのですが、KeyValue の羅列があったり、階層構造が面倒だったりして解析部分が結構面倒です。そういう場合は、クラスにマッピングするのがよいのですが、Yaml 自体の構造と同じでないといけないのが面倒です。
そのあたりを、なんかいい感じに ExDoc を使って検索します。

上記のコードを動かすと以下のような結果が取れます。

key:key-xxxx pass:password

このあたりの暗黙のキャストと要素名の使い方は、調べてみると Json.NET でも似たものがありました。

Json.NET – Modifying JSON
http://james.newtonking.com/json/help/?topic=html/ModifyJson.htm

JObject に変換した後に、名前付きインデックスで検索ができます。

string rssTitle = (string)rss["channel"]["title"];

ExDoc の場合は、/ 演算子や % 演算子をオーバーライドすることによって、doc * “apikey” のような構文を実現していますが、ああ、なるほど名前付き配列でも十分ですよね。dynamic 版もあって、PHP の XML 風に要素名を連ねることもできます。
内部構造的には、同じことをやっているので、同じ構文が使えても良いかなと思っています。

ExDoc.Json も同じ

ExDoc.Json も作ってみましたが、内部的には ExDoc.Yaml と変わりません。Yaml も Json もハッシュとリストでできているので、似た感じの XML が出来上がります。ただし、Json の場合、長いデータもハッシュに置くことが多いので、ハッシュ値を属性に置くか、要素に置くかの選択ができるようにしました。

public void demo1()
{
    string json = @"
{
 'CPU': 'Intel',
 'PSU': '500W',
 'Drives': {
  set1: 'DVD read/writer',
  set2: '500 gigabyte hard drive',
  set3: '200 gigabype hard drive'
 },
 'Languages': [
  'C#',
  'F#',
  'Visual Basic'
 ]
}";

    var jdoc = JToken.Parse(json);
    var xdoc = jdoc.ToXDocument();
    Debug.WriteLine(xdoc.ToString());
    var doc = ExDocument.Load(xdoc);

    var lang = doc * "Languages";
    foreach (var it in lang)
    {
        Debug.WriteLine("lang" + (string)it);
    }
}

こんな風に入れ子になった JSON の場合、Drives のハッシュをそのまま属性にしてしまうと、ちょっと見づらくなります。

<root CPU="Intel" PSU="500W">
  <Drives set1="DVD read/writer" set2="500 gigabyte hard drive" set3="200 gigabype hard drive" />
  <Languages>C#</Languages>
  <Languages>F#</Languages>
  <Languages>Visual Basic</Languages>
</root>

XML に変換するときに要素出力を優先(XmlPriority.Element)にしておくと、

    var xdoc = jdoc.ToXDocument(XmlPriority.Element);

下記のように、すべてのデータが要素になりようにします。XML 形式にしてしまうと冗長ですが、XElement で LINQ したり、ExDoc で検索したりするときには便利でしょう。

<root>
  <CPU>Intel</CPU>
  <PSU>500W</PSU>
  <Drives>
    <set1>DVD read/writer</set1>
    <set2>500 gigabyte hard drive</set2>
    <set3>200 gigabype hard drive</set3>
  </Drives>
  <Languages>C#</Languages>
  <Languages>F#</Languages>
  <Languages>Visual Basic</Languages>
</root>

ちなみに、Json.NET の内部構造を探っているときに分かったのですが、XPath のような仕組みを作るためにパス部分(ハッシュ名)をすべて持っているんですよね。ハイパフォーマンスな分、メモリは食うかもしれません….が、Web API でやり取りするぐらいのでデータならば別にどうということはないのですが。

追記:2014/10/29
Languages のところが、リストっぽくなくてアクセスしにくいので item タグを使うように変更しよう。

<Languages>
 <item>C#</item>
 <item>F#</item>
 <item>Visual Basic</item>
</Languages>

 

今後の予定

だいたいは思う通りに動いたので、今度は値を変更するところを実装しようかなと思ってます。以前、少し実装はしてみたもの、ExDoc の / 演算子と相性が悪くて、どうもうまくいかないのですが、Json.NET のように KeyValue を使って添え字に名前を使えば、書式が簡単になりそうです。

doc._["Languages"][2] = "Visual Basic.NET" ;

な感じで変更できればよいかと。

あと、XLTS か Xml schema な感じで、元の XDocument 構造を他の XDocument にマッピングする写像っぽい使い方ができると良いと思ってます。複雑な XML や乱雑な HTML データから、目的の XML データを取り出すみたいな使い方です。クエリを使って、直接 XML フォーマット(この場合は XElement ツリー)を作るところまでできれば、後は Json や Yaml に再フォーマットするのは難しくはないかと思ってます。

カテゴリー: 開発, C#, EXDoc | ヒアドキュメントっぽく Yaml を書くための ExDoc.Yaml をリリース はコメントを受け付けていません

新 Mac mini で Xamarin 環境を整える

先日発売された Mac mini http://store.apple.com/jp/buy-mac/mac-mini に Xamarin 環境を構築しています。1.4 GHz Mac mini で直前よりもランクが落ちる感じで、なんだかなーという感じなのですが、まあ、それはそれとしてセッティング。実は、mac mini の新型は出ないと思って、発表の直前に注文はしたんですよね…でもって、発表があったものだからキャンセルをして注文し直したという…。CPU スペック的には mac book air と同じなので開発環境としては問題ないんでしょうが。ディスクが HDD なのがちょっと気になるところです。念のため、メモリは 8GB にアップさせています。ちなみに、ストレージを SSD にアップグレードしてしまうと、Mac book air と同じ値段になってしまう(苦笑)なので、そっちがお勧めです。

https://pbs.twimg.com/media/B0rkkbNCAAAjl3L.jpg:large

上にあるのが新 mac mini で、下にあるのが前々 mac mini ですね。前々 mac mini は core 2 なので今となっては結構遅いです(当時としてもあまり早いほうではなかった気が。入門版の位置づけだったので)。

開発環境として使う

手元の mac book air もそうなのですが、完全に開発環境として使っていて、メールの設定や Office 製品のインストールすらしていません。画面キャプチャ用のツールと、リモートデスクトップ関連のツールだけしか入っていないという環境です。
仮想環境は使わず、PC からリモートで動かすのみなので、ストレージの容量はそれほど必要ありません。なので、HDD よりも SSD のほうが適しているのですが、まあ、対費用効果を鑑みてというところですね。仮想環境上で Windows + Visual Studio を動かす場合は、到底 mac mini のスペックでは無理です。

  • Xamarin Studio
  • Xamarin Android Player
  • splashtop personal

だけの環境です。Windows のほうで VNC クライアントを使えば、splashtop を入れる必要はないのですが、日本語の 109 キーボードが誤認識するので、これを使っています…が、後述するように 新しい mac mini というか yosemite は日本語キーボード自体を認識しないようで、splashtop をつかっても VNC を使ってもキーボードに関しては US キーボードを使っていると同じ状態になります。

Visual Studio から iOS シミュレータに接続する

Xamarin.iOS のバージョンを Windows/Mac で揃えて、すんなりと動きます。特に動作が遅いというわけでもなさそうです。ネットワーク的に頻繁に PC とアクセスするので、WiFi 接続よりも有線LAN接続にしておいたほうが無難でしょう。

image

初期状態の場合、iOS シミュレータは、8.1 しか入っていないので、念のため iOS 7.1 のも入れておきます。Xcode を開いて、「Xcode」→「Preference」で、Downloads のタブを開くと旧バージョンの iOS 7.1 Simulator をダウンロードできます。

image

この mac 自体が新品なので、それ以前のバージョンをダウンロードできませんが、xcode を古くすれば大丈夫なのかな?

一日ほどぱらぱらと動かしてていた感じでは開発環境としては問題ありません。時折、Xamarin Studio で重たい感じがするのはキャッシュの類でしょう。SSD ならば、この手のアクセス不具合が減るのですが、直接 Mac 上の Xamarin Studio で編集することは少ないので、これで十分です。手元にあるのが、前々 mac なので、かなり遅くて閉口したためかもしれません。

Xamarin Studio で iOS シミュレーターを動かした状態です。

image

日本語キーボードが認識されにくい

以前の mac mini の問題として日本語の jis キーボードが認識されませんでした。これは、jis 109 のキーボードレイアウトが mac mini だけ持っていない(mac book air とかは持っている)ので、VNC で接続すると、@ が打てなくて(場所が変わっていて)プログラミングがしにくかったんですよね。@ は、objective-C で頻繁に出てくるので、結構なストレスなのです。

splashtop を使うと、この問題が回避されて、本来の日本語キーボードのレイアウト通りに表示されるようになっていたのですが、新 mac mini では、その問題が再発生しています。

「認識されにくい」と書くのは、たまにきちんと認識されるからです。どういうタイミングなのか分かりませんが、接続状態によって US キーボードに間違われたり、日本語キーボードとして正しく認識されたりします。

image

キーボードの設定を見ると、英字のレイアウトが「U.S.」になってしまいます。実は、この選択肢に Japanese が現れないので、mac mini は以前どおり、日本語キーボードのレイアウトは存在しないのかもしれません。これが mac book air の場合には入っているので、何らかのハードウェア的な制限かもしれません。

Yosemite で Windows からのファイル共有ができなくなった?

新しい OS X ( Yosemite ) では、最初のログインに iCloud に連携させた Apple ID(でいいのかな?)が使われます。なんとなく、Apple ID のほうに統合しておくと、Windows とのファイル共有ができなくなります。

本来ならば、SMB を使うにチェックを入れて、ユーザーのアカウントにチェックを入れれば、Windows からファイル共有でフォルダへの読み書きができるようになるのですが、ここのチェックが入れられなくなります。おそらく、Apple ID で管理するので、Windows から ユーザ名/パスワードでアクセスできない、ってことなのでしょうが非常に不便です。

image

PC と Mac 間でファイルのやり取りをするときに、PC からコピーができなくなります。

回避策としては、

  1. アクセス用にユーザ名/パスワード形式で、ログインユーザーを新しく作る。
  2. 「共有フォルダ」にアクセス用のフォルダを「+」で追加する。
  3. アクセス用ユーザーを、ユーザーに「+」で追加する。
  4. アクセス用ユーザーに、自分のフォルダへのアクセス権限「読み/書き」を与える。

image

私の場合「増田智明(masuda)」というユーザーで普段はログインしておいて、Windows からファイル共有するときは tomoaki というユーザーを使うことになります。Windows からネットワークでアクセスする時に、初回だけユーザー名とパスワードが必要になります。後は、Windows が覚えておいてくれるので(時々忘れますが)、普段通りアクセスできます。

image

アクセス設定をした直後は、うまく設定が反映されていないことが多いので、しばらくして Windows のネットワークを最新にしてアクセスしてみてください。多人数のネットワークの時は、セキュリティ上の問題がありますが、ローカルの開発環境では大丈夫でしょう。

値段的にどうなのか?

実は、開発環境を整えるだけでも結構な値段になります。Visual Studio + Xamarin.iOS の組み合わせだけで年間20万円は下りません。私の場合 Microsoft MVP の関係で、どちらも無料で使っているので mac mini を揃えるだけで済むのですが、個人的な開発をする場合、この金額は結構な負担です。今回の mac mini は最低ランクの 1.6 GHz ですが、メモリだけを 8GB にアップグレードしました。消費税を入れて 7万円弱というところなのです。これ以上のスペックを求めると、先に書いた通り mac book air とほとんど値段が変わりません。おそらく、mac book air も mac mini と CPU スペックは変わらないので、ディスプレイが付いているし、キーボードが付いているし、SSD だし、で良いことづくめです。なので、10万円程度の予算があれば、mac book air のほうがベターでしょう。そういう意味では、5万円ちょっと10万円以下の層で構築するのがベターなような気がします。

そうなると、SSD へのアップグレードとかは色々諦めて、最初のエントリーレベルとしての mac mini 購入を考えたほうがよさそうです。勿論、開発環境でなければ(インテリアとしても含めて)もうちょっと HDD が欲しいところですが、そうなるとディスプレイ付きで iMac にしてしまったほうが良いという感じですね。私の場合、スペースの関係上ディスプレイは必要ないので iMac よりは mac mini のほうが適切なのですが。どちらにせよ、同レベルの PC を買うよりは割高になるのは仕方がないところです。

カテゴリー: 開発 | 新 Mac mini で Xamarin 環境を整える はコメントを受け付けていません

F# の判別共用体を C# で使いやすいようにキャストする

F# で lex/yacc っぽいものを作っていると判別共用体(Discriminated Unions)が便利なので、よく使うのでうのですが「C# で使う時はどうするのか?」と聞かれて、はて?と思ってしまいました。Xamarin.Forms のパーサを作っているときは、そのあたりは微妙に避けて(よくわからなかったので)C# からは直接判別共用体を使わないような工夫をしています。

が、Optional を使ったり Choice を使ったりすると(私自身は使ってないけど)、このあたりはどうするのか?って話です。

判別共用体を作る

他の場合も一緒だと思うので、元ネタの判別共用体を作ります。C/C++ で言えば union なので、そんなに違和感はありません。

type A =
    | STR of string
    | INT of int
    | KEYVALUE of key:string * value:string

判別共用体を使う

判別共用体が便利なのは、利用するときに match で判断できるところです。C/C++ の union の場合は type を内部に持たせるだろうし、Variant の場合も似たり寄ったりです。メモリ効率はどうなのかは気になるところですが、そのあたりは .NET なので、別々に持っているのかも。

let go() =
    let message a =
        let msg =
            match a with
            | A.STR(s) -> "string is " + s
            | A.INT(i) -> "int is " + i.ToString()
            | A.KEYVALUE(k,v) -> "pair is " + k + ", " + v
        printfn "%A" msg

    let a = A.STR("masuda")
    message a
    let b = A.KEYVALUE("address","itabashi")
    message b

オブジェクトを作るときは、A.STR あるいは STR で作れて、チェックするときは match で判別します。便利ですね。
これがどのくらい便利かというと、C# に書いてみるとわかります。

C#で判別共用対を使う

まず、A.STR の場合がそのまま使えないので、create のためのメソッドを作っておきます。
Factory パターンで、create します。

type A =
    | STR of string
    | INT of int
    | KEYVALUE of key:string * value:string

    // C# のための create
    static member create(s:string) = STR(s)
    static member create(i:int) = INT(i)
    static member create(k:string, v:string) = KEYVALUE(k,v)

これで、C# から作成するときは、create メソッドを使えばよいことになります。

var a = A.create("masuda");

F# の match の部分はどうなるかというと、結構面倒です。
これは、判別共用体 A クラスの内容をコンソールに出力しているだけなのですが、IsSTR プロパティでチェックをした後に、A.STR でキャストしないといけません。

static void debug( DiscrUnion.A a )
{
    if (a.IsSTR)
    {
        string s = (a as A.STR).Item;
        Console.WriteLine("string is {0}", s);
    }
    else if (a.IsINT)
    {
        int i = (a as A.INT).Item;
        Console.WriteLine("int is {0}", i);
    } else if ( a.IsKEYVALUE )
    {
        string k = (a as A.KEYVALUE).key;
        string v = (a as A.KEYVALUE).value;
        Console.WriteLine("pair is {0}, {1}", k, v);
    }
    else
    {
        Console.WriteLine("error");
    }
}

F# の match に比べるとかなり冗長な感じです。

これが面倒なので、C# に判別共用体クラスを公開するのはやめていたのですが、どうしても公開する必要があるならば、キャストを作ればよかろう、ってことに先日気づきました。
F# でも op_Explicit や op_Implicit メソッドを書くことによって、明示的なキャストと暗黙のキャストを作ることができます。

C# に公開するキャストメソッドを作る

type A =
    | STR of string
    | INT of int
    | KEYVALUE of key:string * value:string

    // C# のための create
    static member create(s:string) = STR(s)
    static member create(i:int) = INT(i)
    static member create(k:string, v:string) = KEYVALUE(k,v)

    // C# のための明示的なキャスト用
    static member op_Explicit (a:A) : string =
        match a with
        | A.STR(s) -> s
        | _ -> ""
    static member op_Explicit (a:A) : int =
        match a with
        | A.INT(i) -> i
        | _ -> 0
    static member op_Explicit (a:A) : System.Tuple<string,string> =
        match a with
        | A.KEYVALUE(k,v) -> new System.Tuple<string,string>(k,v)
        | _ -> new System.Tuple<string,string>("","")

    // こっちのほうが便利
    member this.ToKeyValue(): System.Tuple<string,string> =
        match this with
        | A.KEYVALUE(k,v) -> new System.Tuple<string,string>(k,v)
        | _ -> new System.Tuple<string,string>("","")

op_Explicit メソッドを作っておくと C# で (string)a のように明示的にキャストしたときと同じになります。

var a = A.create("masuda");
string aa = (string)a;

いちいち、IsSTR でチェックしなくてよいので、これでよさそうですね。先の op_Explicit メソッドでは string 以外のときは “” で空文字列を返していますが、failwith にして例外にしてもよいでしょう。

KeyValue のような Tuple を返す時には、F# のものを返しても良いのですが、System.Tuple に書き直しています。このため、キャスト自体が面倒で、下記なことになります。

var b = A.create("name", "tomoaki");
var bb = (Tuple<string, string>)b;
Console.WriteLine("bb is tuple {0}, {1}", bb.Item1, bb.Item2);

型推論の var で受ければよいのでは?と思うところですが、var で受けてしまうと判別共用体の A クラスのままになるので都合が悪いのです。
こういう場合は、素直に ToKeyValue メソッドを作って、インテリセンスを効かせたほうが分かりやすいでしょう。

as ではキャストできない

実は、ひとつ落とし穴があって、a as string のようなキャストはできません。変数 a は A クラスなので、as で Type チェックをすると A 自身が返ってくるためです。なので、(string)a のように「明示的にキャスト」をしないといけないという罠に陥ります。このあたりは、ローカルルールということで、要注意です。

あと、暗黙のキャストを作ろうとすると「暗黙のキャスト」以外ができなくなります。先の op_Explicit を op_Implict に書き換えると、暗黙のキャストになって (string) 部分が要らなくて便利そうなのですが、逆に (string) を付けるとコンパイルエラーになる、という不思議なことになります。

// 暗黙のキャストを使う
string aa = a;

これはこれで、var が使えなくなるので不便な感じですよね。また、op_Explicit と op_Implict は同時に定義できないので、どちらか一方だけを使うことになります。これも変な仕様ですが、まあ、そのあたりも含めて注意して作ると、うまく C# で使える判別共用体が作れます。

カテゴリー: C#, F# | F# の判別共用体を C# で使いやすいようにキャストする はコメントを受け付けていません