特集
» 2013年04月26日 11時46分 公開

開発者が知っておくべき、ライブラリとしてのWindowsランタイム特集:デスクトップでもWinRT活用(5/5 ページ)

[荒井省三,日本マイクロソフト]
前のページへ 1|2|3|4|5       

WinRTの応用的な使い方(非同期編)

 Visual Studio 2012に含まれるC# 5.0とVisual Basic 11.0には、非同期処理を容易にするために「async/await」という言語機能*8が導入されている。応用編では、WinRTの非同期メソッドをasync/awaitで記述することを目的としている。いきなりコードを提示したいところだが、Windowsストア・アプリのプロジェクトと違って、準備が必要になる。では、具体的な作業を使って説明していく。

*8 正確には、コンパイラに対する特別な指示を意味するキーワードとなる。この意味では、「コンパイラ・ディレクティブ」と呼んでもよいと考えるが、より現代風に呼ぶのであれば「非同期用のDSL(ドメイン固有言語)」と呼ぶのがふさわしいはずだ。


1. プロジェクトへの参照設定の追加

 [ソリューション エクスプローラー]を使って[参照設定]−[参照の追加]をクリックして、次に示すライブラリへの参照設定を行う(次の画面はその実施例)。

  • %ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.Treading.Tasks.dllファイル
  • %ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dllファイル
System.Threading.Tasks.dllファイルへの参照の追加 System.Threading.Tasks.dllファイルへの参照の追加
必要なライブラリへの参照設定を行う。
  (1)[ブラウズ]タブをクリック。
  (2)[参照]ボタンをクリックして、「%ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Facades\System.Threading.Tasks.dll」ファイルを選択する。
  (3)[OK]ボタンをクリックして参照設定を終了する。

 System.Threading.Tasks.dllファイルへの参照を追加したら、次にSystem.Runtime.WindowsRuntime.dllファイルへの参照を追加する。

System.Runtime.WindowsRuntime.dllへの参照の追加 System.Runtime.WindowsRuntime.dllへの参照の追加
必要なライブラリへの参照設定を行う。
  (1)[ブラウズ]タブをクリック。
  (2)[参照]ボタンをクリックして、「%ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll」ファイルを選択する。
  (3)[OK]ボタンをクリックして参照設定を終了する。

 これでaswync/awaitを使用する準備の完了である。次は、具体的なコードを説明していく。

参照するアセンブリについて

 System.Threading.TasksアセンブリとSystem.Runtime.WindowsRuntimeアセンブリへの参照を追加して、コンソール・アプリでasync/awaitを使用する方法は、ドキュメント化されていない方法である。公開されているサンプルには、非同期メソッドを使用していても同期的な処理を行うコードしかない。この意味において、ここで説明している方法はハック行為の一種と考えるべきである。筆者がこの方法に気が付いたのは、Windowsストア・アプリにおいて、.NET FrameworkのTaskクラスとWinRTの非同期基盤がどのように連携しているかを調べたためだ。もちろん、マイクロソフトの公式サポートがあるわけではない。この点を踏まえて、あくまでも自己責任で利用してほしい。


2.async/awaitを使った非同期プログラミング

 次に示すのが、async/awaitを使って書き直したコードになる。名前空間の使用は、基本的な使い方で説明したものと同じであることから割愛している(実行結果は、基本的な使い方で示したものと同じである)。

static void Main(string[] args)
{
  var task = GetDeviceInformation();   // …… (1)
  while (!task.IsCompleted )   // …… (2)
  {
    System.Threading.Thread.Sleep(500);
  }
  Console.ReadKey();
}

static async Task GetDeviceInformation()   // …… (3)
{
  DeviceInformationCollection deviceCollection;
  deviceCollection = await DeviceInformation.FindAllAsync();   // …… (4)
  foreach (DeviceInformation device in deviceCollection)   // …… (5)
  {
    Console.WriteLine("Name={0}, ID={1}", device.Name, device.Id);
  }
}

Sub Main()
  Dim task = New Task(Async Sub() Await GetDeviceInformation())   ' …… (1)
  task.Start()
  While (Not task.IsCompleted)   ' …… (2)
    System.Threading.Thread.Sleep(500)
  End While
  Console.WriteLine("Dummy")
  Console.ReadKey()
End Sub

Async Function GetDeviceInformation() As Task   ' …… (3)
Dim deviceCollection As DeviceInformationCollection
  deviceCollection = Await DeviceInformation.FindAllAsync()   ' …… (4)
  For Each device As DeviceInformation In deviceCollection   ' …… (5)
    Console.WriteLine("Name={0}, ID={1}", device.Name, device.Id)
  Next
End Function

リスト5 async/awaitでWinRTを使用する(上:C#、下:VB)
async/awaitを使って前述のサンプル・コードを書き直したもの。
  (1)定義した非同期メソッドを呼び出す。
  (2)非同期メソッドが完了するまでを待機させるためのループで、500ミリ秒間隔でチェックする。
  (3)FindAllAsyncを呼び出すための非同期メソッドを定義する(戻り値をTask型にしている)。
  (4)await/awaitキーワードを使って、DeviceInformation.FindAllAsyncメソッドを呼び出す。
  (5)DeviceInformationCollectionを列挙して、デバイス情報をコンソールへ出力する。

 このコードでは、async/awaitを使用するために、GetDeviceInformationメソッドを定義しており、このメソッド内でFindAllAsyncメソッドを待機呼び出し(await)している。これは、メソッドに記述するasyncキーワードをエントリ・ポイントとなるメイン・メソッドに記述できないからだ*9。最も基本的な方法で説明した同期コードと比較すれば、GetDeviceInformationメソッドのメリットは明らかなはずである。非同期メソッドをあたかも同期コードのように記述できており、コードの保守容易性が向上するからだ*10

*9 asyncキーワードには、エントリ・ポイント以外にも、クラスのコンストラクタに記述できないという制約もある。


*10 「保守容易性」という言葉は、特別な知識を必要としないで保守できるという意味で使用している。


非同期処理におけるマジック・コードについて

 リスト5では、リスト4までのマジック・コードと大きく変化している箇所があることに気が付いただろうか。特にVisual Basicで顕著になっている。それは、GetDeviceInformationメソッドの呼び出し箇所である。Visual Basic版では、Taskクラスのインスタンスを新しく作成し、Task.StartメソッドでTaskを開始するようになっている。この理由は、GetDeviceInformationメソッドを呼び出しただけではTaskが開始されなかったからである。理由は調べていないが、今回のような作り方ではVisual BasicコンパイラがC#コンパイラと異なる非同期の実装コードを出力しているためかもしれない。さらにTaskクラスのインスタンスを作成した副次効果として、Taskの終了を待った後に「Console.WriteLine("Dummy")」というコードだけで筆者の環境では結果の出力を得られたことだ。このように非同期処理を同期処理に押し込める方法では、さまざまなマジック・コードが必要となる。しかも、マジック・コードは環境依存でもある。この点を踏まえてコードを書く限りは、大きな問題を感じることはないはずだ


  いかがだっただろうか。Windows 8というOS固有のWinRTをデスクトップ・アプリから使用できることを、十分に感じられたのではないだろうか。必要なことは、できないと考えることではなく、できる可能性はないかと身近なことから調べていく努力だ。簡単にあきらめることなく、プログラミング(自分にとってのハック)を楽しんでほしい。最後に次の言葉で、本稿を終了する。

 Enjoy Programming! Let’s Hack!

「特集:デスクトップでもWinRT活用」のインデックス

特集:デスクトップでもWinRT活用

前のページへ 1|2|3|4|5       

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。